<commit_before>/*
 * Implements a user-facing modal confirmation when link has a
 * "data-confirm" attribute using bootstrap's modals. MIT license.
 *
 *   - vjt@openssl.it  Tue Jul  2 18:45:15 CEST 2013
 */
(function ($) {

  /**
   * Builds the markup for a [Bootstrap modal](http://twitter.github.io/bootstrap/javascript.html#modals)
   * for the given `element`. Uses the following `data-` parameters to
   * customize it:
   *
   *  * `data-confirm`: Contains the modal body text. HTML is allowed.
   *                    Separate multiple paragraphs using \n\n.
   *  * `data-commit`:  The 'confirm' button text. "Confirm" by default.
   *  * `data-cancel`:  The 'cancel' button text. "Cancel" by default.
   *  * `data-verify`:  Adds a text input in which the user has to input
   *                    the text in this attribute value for the 'confirm'
   *                    button to be clickable. Optional.
   *  * `data-verify-text`:  Adds a label for the data-verify input. Optional
   *  * `data-focus`:   Define focused input. Supported values are
   *                    'cancel' or 'commit', 'cancel' is default for
   *                    data-method DELETE, 'commit' for all others.
   *
   * You can set global setting using `dataConfirmModal.setDefaults`, for example:
   *
   *    dataConfirmModal.setDefaults({
   *      title: 'Confirm your action',
   *      commit: 'Continue',
   *      cancel: 'Cancel',
   *      fade:   false,
   *      verifyClass: 'form-control',
   *    });
   *
   */

  var defaults = {
    title: 'Are you sure?',
    commit: 'Confirm',
    commitClass: 'btn-danger',
    cancel: 'Cancel',
    cancelClass: 'btn-default',
    fade: true,
    verifyClass: '',
    elements: ['a[data-confirm]', 'button[data-confirm]', 'input[type=submit][data-confirm]'],
    focus: 'commit'
  };

  var settings;

  window.dataConfirmModal = {
    setDefaults: function (newSettings) {
      settings = $.extend(settings, newSettings);
    },

    restoreDefaults: function () {
      settings = $.extend({}, defaults);
    },

    confirm: function (options) {
      // Build an ephemeral modal
      //
      var modal = buildModal (options);

      modal.modal('show');
      modal.on('hidden.bs.modal', function () {
        modal.remove();
      });

      modal.find('.commit').on('click', function () {
        if (options.onConfirm && options.onConfirm.call)
          options.onConfirm.call();

        modal.modal('hide');
      });

      modal.find('.cancel').on('click', function () {
        if (options.onCancel && options.onCancel.call)
          options.onCancel.call();

        modal.modal('hide');
      });
    }
  };

  dataConfirmModal.restoreDefaults();

  var buildElementModal = function (element) {
    var options = {
      title:        element.attr('title') || element.data('original-title'),
      text:         element.data('confirm'),
      focus:        element.data('focus'),
      method:       element.data('method'),
      commit:       element.data('commit'),
      commitClass:  element.data('commit-class'),
      cancel:       element.data('cancel'),
      cancelClass:  element.data('cancel-class'),
      remote:       element.data('remote'),
      verify:       element.data('verify'),
      verifyRegexp: element.data('verify-regexp'),
      verifyLabel:  element.data('verify-text'),
      verifyRegexpCaseInsensitive: element.data('verify-regexp-caseinsensitive')
    };

    var modal = buildModal (options);

    modal.data('confirmed', false);
    modal.find('.commit').on('click', function () {
      modal.data('confirmed', true);
      element.trigger('click');
      modal.modal('hide');
    });

    return modal;
  }

  var buildModal = function (options) {
    var id = 'confirm-modal-' + String(Math.random()).slice(2, -1);
    var fade = settings.fade ? 'fade' : '';

    var modal = $(
      '
' +
        '
' +
          '
' +
            '
' +
              '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
              '

 ' +
            '
' +
            '

' +
            '
' +
              '<button class="btn cancel" data-dismiss="modal" aria-hidden="true"></button>' +
              '<button class="btn commit"></button>' +
            '
'+
          '
'+
        '
'+
      '
'
    );

    // Make sure it's always the top zindex
    var highest = 1050;
    $('.modal.in').not('#'+id).each(function() {
      current = parseInt($(this).css('z-index'), 10);
      if(current > highest) {
        highest = current
      }
    });
    modal.css('z-index', parseInt(highest) + 1);

    modal.find('.modal-title').text(options.title || settings.title);

    var body = modal.find('.modal-body');

    $.each((options.text||'').split(/\n{2}/), function (i, piece) {
      body.append($('
').html(piece));
    });

    var commit = modal.find('.commit');
    commit.text(options.commit || settings.commit);
    commit.addClass(options.commitClass || settings.commitClass);

    var cancel = modal.find('.cancel');
    cancel.text(options.cancel || settings.cancel);
    cancel.addClass(options.cancelClass || settings.cancelClass);

    if (options.remote) {
      commit.attr('data-dismiss', 'modal');
    }

    if (options.verify || options.verifyRegexp) {
      commit.prop('disabled', true);

      var isMatch;
      if (options.verifyRegexp) {
        var caseInsensitive = options.verifyRegexpCaseInsensitive;
        var re = new RegExp(regexp, caseInsensitive ? 'i' : '');

        isMatch = function (input) { return input.match(re) };
      } else {
        isMatch = function (input) { return options.verify == input };
      }

      var verification = $('<input/>', {"type": 'text', "class": settings.verifyClass}).on('keyup', function () {
        commit.prop('disabled', !isMatch($(this).val()));
      });

      modal.on('shown', function () {
        verification.focus();
      });

      modal.on('hide', function () {
        verification.val('').trigger('keyup');
      });

      if (options.verifyLabel)
        body.append($('
', {text: options.verifyLabel}))

      body.append(verification);
    }

    var focus_element;
    if (options.focus) {
      focus_element = options.focus;
    } else if (options.method == 'delete') {
      focus_element = 'cancel'
    } else {
      focus_element = settings.focus;
    }
    focus_element = modal.find('.' + focus_element);

    modal.on('shown.bs.modal', function () {
      focus_element.focus();
    });

    $('body').append(modal);

    return modal;
  };

  /**
   * Returns a modal already built for the given element or builds a new one,
   * caching it into the element's `confirm-modal` data attribute.
   */
  var getModal = function (element) {
    var modal = element.data('confirm-modal') || buildElementModal(element);

    if (modal && !element.data('confirm-modal'))
      element.data('confirm-modal', modal);

    return modal;
  };

  $.fn.confirmModal = function () {
    getModal($(this)).modal('show');

    return this;
  };

  if ($.rails) {
    /**
     * Attaches to the Rails' UJS adapter 'confirm' event on links having a
     * `data-confirm` attribute. Temporarily overrides the `$.rails.confirm`
     * function with an anonymous one that returns the 'confirmed' status of
     * the modal.
     *
     * A modal is considered 'confirmed' when an user has successfully clicked
     * the 'confirm' button in it.
     */
    $(document).delegate(settings.elements.join(', '), 'confirm', function() {
      var element = $(this), modal = getModal(element);
      var confirmed = modal.data('confirmed');

      if (!confirmed && !modal.is(':visible')) {
        modal.modal('show');

        var confirm = $.rails.confirm;
        $.rails.confirm = function () { return modal.data('confirmed'); }
        modal.on('hide', function () { $.rails.confirm = confirm; });
      }

      return confirmed;
    });
  }

})(jQuery);
<commit_msg>adding variable declaration<commit_after>/*
 * Implements a user-facing modal confirmation when link has a
 * "data-confirm" attribute using bootstrap's modals. MIT license.
 *
 *   - vjt@openssl.it  Tue Jul  2 18:45:15 CEST 2013
 */
(function ($) {

  /**
   * Builds the markup for a [Bootstrap modal](http://twitter.github.io/bootstrap/javascript.html#modals)
   * for the given `element`. Uses the following `data-` parameters to
   * customize it:
   *
   *  * `data-confirm`: Contains the modal body text. HTML is allowed.
   *                    Separate multiple paragraphs using \n\n.
   *  * `data-commit`:  The 'confirm' button text. "Confirm" by default.
   *  * `data-cancel`:  The 'cancel' button text. "Cancel" by default.
   *  * `data-verify`:  Adds a text input in which the user has to input
   *                    the text in this attribute value for the 'confirm'
   *                    button to be clickable. Optional.
   *  * `data-verify-text`:  Adds a label for the data-verify input. Optional
   *  * `data-focus`:   Define focused input. Supported values are
   *                    'cancel' or 'commit', 'cancel' is default for
   *                    data-method DELETE, 'commit' for all others.
   *
   * You can set global setting using `dataConfirmModal.setDefaults`, for example:
   *
   *    dataConfirmModal.setDefaults({
   *      title: 'Confirm your action',
   *      commit: 'Continue',
   *      cancel: 'Cancel',
   *      fade:   false,
   *      verifyClass: 'form-control',
   *    });
   *
   */

  var defaults = {
    title: 'Are you sure?',
    commit: 'Confirm',
    commitClass: 'btn-danger',
    cancel: 'Cancel',
    cancelClass: 'btn-default',
    fade: true,
    verifyClass: '',
    elements: ['a[data-confirm]', 'button[data-confirm]', 'input[type=submit][data-confirm]'],
    focus: 'commit'
  };

  var settings;

  window.dataConfirmModal = {
    setDefaults: function (newSettings) {
      settings = $.extend(settings, newSettings);
    },

    restoreDefaults: function () {
      settings = $.extend({}, defaults);
    },

    confirm: function (options) {
      // Build an ephemeral modal
      //
      var modal = buildModal (options);

      modal.modal('show');
      modal.on('hidden.bs.modal', function () {
        modal.remove();
      });

      modal.find('.commit').on('click', function () {
        if (options.onConfirm && options.onConfirm.call)
          options.onConfirm.call();

        modal.modal('hide');
      });

      modal.find('.cancel').on('click', function () {
        if (options.onCancel && options.onCancel.call)
          options.onCancel.call();

        modal.modal('hide');
      });
    }
  };

  dataConfirmModal.restoreDefaults();

  var buildElementModal = function (element) {
    var options = {
      title:        element.attr('title') || element.data('original-title'),
      text:         element.data('confirm'),
      focus:        element.data('focus'),
      method:       element.data('method'),
      commit:       element.data('commit'),
      commitClass:  element.data('commit-class'),
      cancel:       element.data('cancel'),
      cancelClass:  element.data('cancel-class'),
      remote:       element.data('remote'),
      verify:       element.data('verify'),
      verifyRegexp: element.data('verify-regexp'),
      verifyLabel:  element.data('verify-text'),
      verifyRegexpCaseInsensitive: element.data('verify-regexp-caseinsensitive')
    };

    var modal = buildModal (options);

    modal.data('confirmed', false);
    modal.find('.commit').on('click', function () {
      modal.data('confirmed', true);
      element.trigger('click');
      modal.modal('hide');
    });

    return modal;
  }

  var buildModal = function (options) {
    var id = 'confirm-modal-' + String(Math.random()).slice(2, -1);
    var fade = settings.fade ? 'fade' : '';

    var modal = $(
      '
' +
        '
' +
          '
' +
            '
' +
              '<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
              '

 ' +
            '
' +
            '

' +
            '
' +
              '<button class="btn cancel" data-dismiss="modal" aria-hidden="true"></button>' +
              '<button class="btn commit"></button>' +
            '
'+
          '
'+
        '
'+
      '
'
    );

    // Make sure it's always the top zindex
    var highest = current = 1050;
    $('.modal.in').not('#'+id).each(function() {
      current = parseInt($(this).css('z-index'), 10);
      if(current > highest) {
        highest = current
      }
    });
    modal.css('z-index', parseInt(highest) + 1);

    modal.find('.modal-title').text(options.title || settings.title);

    var body = modal.find('.modal-body');

    $.each((options.text||'').split(/\n{2}/), function (i, piece) {
      body.append($('
').html(piece));
    });

    var commit = modal.find('.commit');
    commit.text(options.commit || settings.commit);
    commit.addClass(options.commitClass || settings.commitClass);

    var cancel = modal.find('.cancel');
    cancel.text(options.cancel || settings.cancel);
    cancel.addClass(options.cancelClass || settings.cancelClass);

    if (options.remote) {
      commit.attr('data-dismiss', 'modal');
    }

    if (options.verify || options.verifyRegexp) {
      commit.prop('disabled', true);

      var isMatch;
      if (options.verifyRegexp) {
        var caseInsensitive = options.verifyRegexpCaseInsensitive;
        var re = new RegExp(regexp, caseInsensitive ? 'i' : '');

        isMatch = function (input) { return input.match(re) };
      } else {
        isMatch = function (input) { return options.verify == input };
      }

      var verification = $('<input/>', {"type": 'text', "class": settings.verifyClass}).on('keyup', function () {
        commit.prop('disabled', !isMatch($(this).val()));
      });

      modal.on('shown', function () {
        verification.focus();
      });

      modal.on('hide', function () {
        verification.val('').trigger('keyup');
      });

      if (options.verifyLabel)
        body.append($('
', {text: options.verifyLabel}))

      body.append(verification);
    }

    var focus_element;
    if (options.focus) {
      focus_element = options.focus;
    } else if (options.method == 'delete') {
      focus_element = 'cancel'
    } else {
      focus_element = settings.focus;
    }
    focus_element = modal.find('.' + focus_element);

    modal.on('shown.bs.modal', function () {
      focus_element.focus();
    });

    $('body').append(modal);

    return modal;
  };

  /**
   * Returns a modal already built for the given element or builds a new one,
   * caching it into the element's `confirm-modal` data attribute.
   */
  var getModal = function (element) {
    var modal = element.data('confirm-modal') || buildElementModal(element);

    if (modal && !element.data('confirm-modal'))
      element.data('confirm-modal', modal);

    return modal;
  };

  $.fn.confirmModal = function () {
    getModal($(this)).modal('show');

    return this;
  };

  if ($.rails) {
    /**
     * Attaches to the Rails' UJS adapter 'confirm' event on links having a
     * `data-confirm` attribute. Temporarily overrides the `$.rails.confirm`
     * function with an anonymous one that returns the 'confirmed' status of
     * the modal.
     *
     * A modal is considered 'confirmed' when an user has successfully clicked
     * the 'confirm' button in it.
     */
    $(document).delegate(settings.elements.join(', '), 'confirm', function() {
      var element = $(this), modal = getModal(element);
      var confirmed = modal.data('confirmed');

      if (!confirmed && !modal.is(':visible')) {
        modal.modal('show');

        var confirm = $.rails.confirm;
        $.rails.confirm = function () { return modal.data('confirmed'); }
        modal.on('hide', function () { $.rails.confirm = confirm; });
      }

      return confirmed;
    });
  }

})(jQuery);
<|endoftext|>


<commit_before>'use strict';

angular.module('ngDependencyGraph')
  .factory('tour', function($rootScope, storage) {
    var tour = new Shepherd.Tour({
      defaults: {
        classes: 'shepherd-theme-default shepherd-element shepherd-open',
        showCancelLink: true,
        scrollTo: false
      }
    });

    var onDone = function() {
      storage.saveTourDone();
      $rootScope.$evalAsync();
    };

    tour.on('complete', onDone);
    tour.on('cancel', onDone);
    tour.on('hide', onDone);

    var buttons = {
      step: [{
        text: 'Next',
        action: tour.next
      }],
      finish: [{
        text: 'Finish',
        action: tour.next
      }]
    };

    var steps = {

      welcome: {
        text: 'Welcome to AngularJS dependency graph browser.',
        buttons: buttons.step
      },

      chooseScope: {
        text: 'Switch between modules and components view here.',
        attachTo: '.choose-scope bottom',
        buttons: buttons.step
      },

      ignoreModules: {
        text: 'Use \'Ignore\' field to hide modules you don\'t want to see...',
        attachTo: '.options__ignore left',
        buttons: buttons.step
      },

      filterModules: {
        text: '...and/or \'Filter\' field to specify which modules you want to see.',
        attachTo: '.options__filter left',
        buttons: buttons.step
      },

      stickyNodes: {
        text: 'If you\'d like your nodes to stay where you drag them - make nodes sticky.

Double click node to unstick.',
        attachTo: '.options__sticky-nodes left',
        buttons: buttons.step
      },

      activeDependencyTree: {
        text: 'Checked \'show active only\' to see dependecied in used.
If you\'d like to see whole tree with more available dependencies uncheck the option.',
        attachTo: '.options__active-tree left',
        buttons: buttons.step
      },

      triggerComponents: {
        text: 'You can filter components nodes by component type.',
        attachTo: '.trigger-components right',
        buttons: buttons.step
      },

      search: {
        text: 'To focus on particular component or module, use search field.',
        attachTo: '.search right',
        buttons: buttons.step
      },

      saving: {
        text: 'The graph is automatically updated with dependencies as you work on your app and refresh the browser.

All options are saved for each of your projects.',
        buttons: buttons.step
      },

      finish: {
        text: 'That\'s it! :) Hope you enjoy.

You can restart this tour by clicking \'Tutorial\' in the bottom right corner.

Please star if you like it:

' +
          '',
        attachTo: '.search right',
        buttons: buttons.finish
      }

    };

    _.each(steps, function(step) {
      tour.addStep(step);
    });

    return tour;

  });
<commit_msg>zoom tutoring<commit_after>'use strict';

angular.module('ngDependencyGraph')
  .factory('tour', function($rootScope, storage) {
    var tour = new Shepherd.Tour({
      defaults: {
        classes: 'shepherd-theme-default shepherd-element shepherd-open',
        showCancelLink: true,
        scrollTo: false
      }
    });

    var onDone = function() {
      storage.saveTourDone();
      $rootScope.$evalAsync();
    };

    tour.on('complete', onDone);
    tour.on('cancel', onDone);
    tour.on('hide', onDone);

    var buttons = {
      step: [{
        text: 'Next',
        action: tour.next
      }],
      finish: [{
        text: 'Finish',
        action: tour.next
      }]
    };

    var steps = {

      welcome: {
        text: 'Welcome to AngularJS dependency graph browser.',
        buttons: buttons.step
      },

      chooseScope: {
        text: 'Switch between modules and components view here.',
        attachTo: '.choose-scope bottom',
        buttons: buttons.step
      },

      ignoreModules: {
        text: 'Use \'Ignore\' field to hide modules you don\'t want to see...',
        attachTo: '.options__ignore left',
        buttons: buttons.step
      },

      filterModules: {
        text: '...and/or \'Filter\' field to specify which modules you want to see.',
        attachTo: '.options__filter left',
        buttons: buttons.step
      },

      stickyNodes: {
        text: 'If you\'d like your nodes to stay where you drag them - make nodes sticky.

Double click node to unstick.',
        attachTo: '.options__sticky-nodes left',
        buttons: buttons.step
      },

      activeDependencyTree: {
        text: 'Checked \'show active only\' to see dependecied in used.
If you\'d like to see whole tree with more available dependencies uncheck the option.',
        attachTo: '.options__active-tree left',
        buttons: buttons.step
      },

      triggerComponents: {
        text: 'You can filter components nodes by component type.',
        attachTo: '.trigger-components right',
        buttons: buttons.step
      },

      search: {
        text: 'To focus on particular component or module, use search field.',
        attachTo: '.search right',
        buttons: buttons.step
      },

      zoom: {
        text: 'To zoom in or zoom out
 alternate zoom option:  use mouse wheel',
        attachTo: '.zoom-in-out bottom',
        buttons: buttons.step
      },

      saving: {
        text: 'The graph is automatically updated with dependencies as you work on your app and refresh the browser.

All options are saved for each of your projects.',
        buttons: buttons.step
      },

      finish: {
        text: 'That\'s it! :) Hope you enjoy.

You can restart this tour by clicking \'Tutorial\' in the bottom right corner.

Please star if you like it:

' +
          '',
        attachTo: '.search right',
        buttons: buttons.finish
      }

    };

    _.each(steps, function(step) {
      tour.addStep(step);
    });

    return tour;

  });
<|endoftext|>


<commit_before>/**
 * Storage内容仓库模块
 *
 * @author Kener (@Kener-林峰, linzhifeng@baidu.com)
 *         errorrik (errorrik@gmail.com)
 */

define(
    function (require) {
        var util = require('./tool/util');
        var _idBase = 0x2311; // 图形数据id自增基础

        /**
         * 唯一标识id生成
         *
         * @inner
         * @param {string=} idHead 标识前缀
         */
        function newShapeId(idHead) {
            return (idHead || '') + (++_idBase);
        }

        /**
         * 快速判断标志~
         *
         * @inner
         * @param e.__silent 是否需要hover判断
         * @param e.__needTransform 是否需要进行transform
         * @param e.style.__rect 区域矩阵缓存，修改后清空，重新计算一次
         */
        function mark(e) {
            if (e.hoverable || e.onclick || e.draggable
                || e.onmousemove || e.onmouseover || e.onmouseout
                || e.onmousedown || e.onmouseup
                || e.ondragenter || e.ondragover || e.ondragleave
                || e.ondrop
            ) {
                e.__silent = false;
            }
            else {
                e.__silent = true;
            }

            if (Math.abs(e.rotation[0]) > 0.0001
                || Math.abs(e.position[0]) > 0.0001
                || Math.abs(e.position[1]) > 0.0001
                || Math.abs(e.scale[0] - 1) > 0.0001
                || Math.abs(e.scale[1] - 1) > 0.0001
            ) {
                e.__needTransform = true;
            }
            else {
                e.__needTransform = false;
            }

            e.style = e.style || {};
            e.style.__rect = null;
        }

        /**
         * 内容仓库 (M)
         *
         * @param {Object} shape 图形库
         */
        function Storage(shape) {
            // 所有常规形状，id索引的map
            this._elements = {};

            // 所有形状的z轴方向排列，提高遍历性能，zElements[0]的形状在zElements[1]形状下方
            this._zElements = [];

            // 高亮层形状，不稳定，动态增删，数组位置也是z轴方向，靠前显示在下方
            this._hoverElements = [];

            // 最大zlevel
            this._maxZlevel = 0;

            // 有数据改变的zlevel
            this._changedZlevel = {};
        }

        /**
         * 遍历迭代器
         *
         * @param {Function} fun 迭代回调函数，return true终止迭代
         * @param {Object=} option 迭代参数，缺省为仅降序遍历常规形状
         *     hover : true 是否迭代高亮层数据
         *     normal : 'down' | 'up' | 'free' 是否迭代常规数据，迭代时是否指定及z轴顺序
         */
        Storage.prototype.iterShape = function (fun, option) {
            if (!option) {
                option = {
                    hover: false,
                    normal: 'down'
                };
            }
            if (option.hover) {
                //高亮层数据遍历
                for (var i = 0, l = this._hoverElements.length; i < l; i++) {
                    if (fun(this._hoverElements[i])) {
                        return self;
                    }
                }
            }

            var zlist;
            var len;
            if (typeof option.normal != 'undefined') {
                //z轴遍历: 'down' | 'up' | 'free'
                switch (option.normal) {
                    case 'down':
                        // 降序遍历，高层优先
                        var l = this._zElements.length;
                        while (l--) {
                            zlist = this._zElements[l];
                            if (zlist) {
                                len = zlist.length;
                                while (len--) {
                                    if (fun(zlist[len])) {
                                        return this;
                                    }
                                }
                            }
                        }
                        break;
                    case 'up':
                        //升序遍历，底层优先
                        for (var i = 0, l = this._zElements.length; i < l; i++) {
                            zlist = this._zElements[i];
                            if (zlist) {
                                len = zlist.length;
                                for (var k = 0; k < len; k++) {
                                    if (fun(zlist[k])) {
                                        return this;
                                    }
                                }
                            }
                        }
                        break;
                    // case 'free':
                    default:
                        //无序遍历
                        for (var i in this._elements) {
                            if (fun(this._elements[i])) {
                                return this;
                            }
                        }
                        break;
                }
            }

            return this;
        };

        /**
         * 修改
         *
         * @param {string} idx 唯一标识
         * @param {Object} params]参数
         * @param {boolean} fast
         */
        Storage.prototype.mod = function (shapeId, params, fast) {
            var e = this._elements[shapeId];
            if (e) {
                this._changedZlevel[e.zlevel] = true;    // 可能修改前后不在一层
                if (params) {
                    if (fast) {
                        util.mergeFast(
                            e,
                            params,
                            true,
                            true
                        );
                    } else {
                        util.merge(
                            e,
                            params,
                            {
                                'overwrite': true,
                                'recursive': true
                            }
                        );
                    }
                }
                mark(e);
                this._changedZlevel[e.zlevel] = true;    // 可能修改前后不在一层
                this._maxZlevel = Math.max(this._maxZlevel, e.zlevel);
            }

            return this;
        };

        /**
         * 常规形状位置漂移，形状自身定义漂移函数
         *
         * @param {string} idx 形状唯一标识
         */
        Storage.prototype.drift = function (shapeId, dx, dy) {
            var e = this._elements[shapeId];
            if (!e) {
                return;
            }
            e.__needTransform = true;
            if (!e.ondrift //ondrift
                //有onbrush并且调用执行返回false或undefined则继续
                || (e.ondrift && !e.ondrift(e, dx, dy))
            ) {
                var zrender = require('./zrender');
                if (zrender.catchBrushException) {
                    try {
                        shape.get(e.shape).drift(e, dx, dy);
                    }
                    catch(error) {
                        zrender.log(error, 'drift error of ' + e.shape, e);
                    }
                }
                else {
                    shape.get(e.shape).drift(e, dx, dy);
                }
            }

            this._changedZlevel[e.zlevel] = true;

            return this;
        };

        /**
         * 添加高亮层数据
         *
         * @param {Object} params 参数
         */
        Storage.prototype.addHover = function (params) {
            if ((params.rotation && Math.abs(params.rotation[0]) > 0.0001)
                || (params.position
                    && (Math.abs(params.position[0]) > 0.0001
                        || Math.abs(params.position[1]) > 0.0001))
                || (params.scale
                    && (Math.abs(params.scale[0] - 1) > 0.0001
                    || Math.abs(params.scale[1] - 1) > 0.0001))
            ) {
                params.__needTransform = true;
            }
            else {
                params.__needTransform = false;
            }

            this._hoverElements.push(params);
            return this;
        };

        /**
         * 删除高亮层数据
         */
        Storage.prototype.delHover = function () {
            this._hoverElements = [];
            return this;
        };

        Storage.prototype.hasHoverShape = function () {
            return this._hoverElements.length > 0;
        };

        /**
         * 添加
         *
         * @param {Object} params 参数
         */
        Storage.prototype.add = function (params) {
            // 默认&必须的参数
            var e = {
                'shape': 'circle',                      // 形状
                'id': params.id || newShapeId(),   // 唯一标识
                'zlevel': 0,                            // z轴位置
                'draggable': false,                     // draggable可拖拽
                'clickable': false,                     // clickable可点击响应
                'hoverable': true,                      // hoverable可悬浮响应
                'position': [0, 0],
                'rotation' : [0, 0, 0],
                'scale' : [1, 1, 0, 0]
            };
            util.merge(
                e,
                params,
                {
                    'overwrite': true,
                    'recursive': true
                }
            );
            mark(e);
            this._elements[e.id] = e;
            this._zElements[e.zlevel] = this._zElements[e.zlevel] || [];
            this._zElements[e.zlevel].push(e);

            this._maxZlevel = Math.max(this._maxZlevel, e.zlevel);
            this._changedZlevel[e.zlevel] = true;

            return this;
        };

        /**
         * 根据指定的shapeId获取相应的shape属性
         *
         * @param {string=} idx 唯一标识
         */
        Storage.prototype.get = function (shapeId) {
            return this._elements[shapeId];
        };

        /**
         * 删除，shapeId不指定则全清空
         *
         * @param {string= | Array} idx 唯一标识
         */
        Storage.prototype.del = function (shapeId) {
            if (typeof shapeId != 'undefined') {
                var delMap = {};
                if (!(shapeId instanceof Array)) {
                    // 单个
                    delMap[shapeId] = true;
                }
                else {
                    // 批量删除
                    if (shapeId.lenth < 1) { // 空数组
                        return;
                    }
                    for (var i = 0, l = shapeId.length; i < l; i++) {
                        delMap[shapeId[i].id] = true;
                    }
                }
                var newList;
                var oldList;
                var zlevel;
                var zChanged = {};
                for (var sId in delMap) {
                    if (this._elements[sId]) {
                        zlevel = _elements[sId].zlevel;
                        this._changedZlevel[zlevel] = true;
                        if (!zChanged[zlevel]) {
                            oldList = this._zElements[zlevel];
                            newList = [];
                            for (var i = 0, l = oldList.length; i < l; i++){
                                if (!delMap[oldList[i].id]) {
                                    newList.push(oldList[i]);
                                }
                            }
                            this._zElements[zlevel] = newList;
                            zChanged[zlevel] = true;
                        }

                        delete this._elements[sId];
                    }
                }
            }
            else{
                // 不指定shapeId清空
                this._elements = {};
                this._zElements = [];
                this._hoverElements = [];
                this._maxZlevel = 0;         //最大zlevel
                this._changedZlevel = {      //有数据改变的zlevel
                    all : true
                };
            }

            return this;
        };

        Storage.prototype.getMaxZlevel = function () {
            return this._maxZlevel;
        };

        Storage.prototype.getChangedZlevel = function () {
            return this._changedZlevel;
        };

        Storage.prototype.clearChangedZlevel = function () {
            this._changedZlevel = {};
            return this;
        };

        Storage.prototype.setChangedZlevle = function (level) {
            this._changedZlevel[level] = true;
            return this;
        };

        /**
         * 释放
         */
        Storage.prototype.dispose = function () {
            this._elements = null;
            this._zElements = null;
            this._hoverElements = null;
        };

        Storage.prototype.newShapeId = newShapeId;

        return Storage;
    }
);
<commit_msg>self -> this<commit_after>/**
 * Storage内容仓库模块
 *
 * @author Kener (@Kener-林峰, linzhifeng@baidu.com)
 *         errorrik (errorrik@gmail.com)
 */

define(
    function (require) {
        var util = require('./tool/util');
        var _idBase = 0x2311; // 图形数据id自增基础

        /**
         * 唯一标识id生成
         *
         * @inner
         * @param {string=} idHead 标识前缀
         */
        function newShapeId(idHead) {
            return (idHead || '') + (++_idBase);
        }

        /**
         * 快速判断标志~
         *
         * @inner
         * @param e.__silent 是否需要hover判断
         * @param e.__needTransform 是否需要进行transform
         * @param e.style.__rect 区域矩阵缓存，修改后清空，重新计算一次
         */
        function mark(e) {
            if (e.hoverable || e.onclick || e.draggable
                || e.onmousemove || e.onmouseover || e.onmouseout
                || e.onmousedown || e.onmouseup
                || e.ondragenter || e.ondragover || e.ondragleave
                || e.ondrop
            ) {
                e.__silent = false;
            }
            else {
                e.__silent = true;
            }

            if (Math.abs(e.rotation[0]) > 0.0001
                || Math.abs(e.position[0]) > 0.0001
                || Math.abs(e.position[1]) > 0.0001
                || Math.abs(e.scale[0] - 1) > 0.0001
                || Math.abs(e.scale[1] - 1) > 0.0001
            ) {
                e.__needTransform = true;
            }
            else {
                e.__needTransform = false;
            }

            e.style = e.style || {};
            e.style.__rect = null;
        }

        /**
         * 内容仓库 (M)
         *
         * @param {Object} shape 图形库
         */
        function Storage(shape) {
            // 所有常规形状，id索引的map
            this._elements = {};

            // 所有形状的z轴方向排列，提高遍历性能，zElements[0]的形状在zElements[1]形状下方
            this._zElements = [];

            // 高亮层形状，不稳定，动态增删，数组位置也是z轴方向，靠前显示在下方
            this._hoverElements = [];

            // 最大zlevel
            this._maxZlevel = 0;

            // 有数据改变的zlevel
            this._changedZlevel = {};
        }

        /**
         * 遍历迭代器
         *
         * @param {Function} fun 迭代回调函数，return true终止迭代
         * @param {Object=} option 迭代参数，缺省为仅降序遍历常规形状
         *     hover : true 是否迭代高亮层数据
         *     normal : 'down' | 'up' | 'free' 是否迭代常规数据，迭代时是否指定及z轴顺序
         */
        Storage.prototype.iterShape = function (fun, option) {
            if (!option) {
                option = {
                    hover: false,
                    normal: 'down'
                };
            }
            if (option.hover) {
                //高亮层数据遍历
                for (var i = 0, l = this._hoverElements.length; i < l; i++) {
                    if (fun(this._hoverElements[i])) {
                        return this;
                    }
                }
            }

            var zlist;
            var len;
            if (typeof option.normal != 'undefined') {
                //z轴遍历: 'down' | 'up' | 'free'
                switch (option.normal) {
                    case 'down':
                        // 降序遍历，高层优先
                        var l = this._zElements.length;
                        while (l--) {
                            zlist = this._zElements[l];
                            if (zlist) {
                                len = zlist.length;
                                while (len--) {
                                    if (fun(zlist[len])) {
                                        return this;
                                    }
                                }
                            }
                        }
                        break;
                    case 'up':
                        //升序遍历，底层优先
                        for (var i = 0, l = this._zElements.length; i < l; i++) {
                            zlist = this._zElements[i];
                            if (zlist) {
                                len = zlist.length;
                                for (var k = 0; k < len; k++) {
                                    if (fun(zlist[k])) {
                                        return this;
                                    }
                                }
                            }
                        }
                        break;
                    // case 'free':
                    default:
                        //无序遍历
                        for (var i in this._elements) {
                            if (fun(this._elements[i])) {
                                return this;
                            }
                        }
                        break;
                }
            }

            return this;
        };

        /**
         * 修改
         *
         * @param {string} idx 唯一标识
         * @param {Object} params]参数
         * @param {boolean} fast
         */
        Storage.prototype.mod = function (shapeId, params, fast) {
            var e = this._elements[shapeId];
            if (e) {
                this._changedZlevel[e.zlevel] = true;    // 可能修改前后不在一层
                if (params) {
                    if (fast) {
                        util.mergeFast(
                            e,
                            params,
                            true,
                            true
                        );
                    } else {
                        util.merge(
                            e,
                            params,
                            {
                                'overwrite': true,
                                'recursive': true
                            }
                        );
                    }
                }
                mark(e);
                this._changedZlevel[e.zlevel] = true;    // 可能修改前后不在一层
                this._maxZlevel = Math.max(this._maxZlevel, e.zlevel);
            }

            return this;
        };

        /**
         * 常规形状位置漂移，形状自身定义漂移函数
         *
         * @param {string} idx 形状唯一标识
         */
        Storage.prototype.drift = function (shapeId, dx, dy) {
            var e = this._elements[shapeId];
            if (!e) {
                return;
            }
            e.__needTransform = true;
            if (!e.ondrift //ondrift
                //有onbrush并且调用执行返回false或undefined则继续
                || (e.ondrift && !e.ondrift(e, dx, dy))
            ) {
                var zrender = require('./zrender');
                if (zrender.catchBrushException) {
                    try {
                        shape.get(e.shape).drift(e, dx, dy);
                    }
                    catch(error) {
                        zrender.log(error, 'drift error of ' + e.shape, e);
                    }
                }
                else {
                    shape.get(e.shape).drift(e, dx, dy);
                }
            }

            this._changedZlevel[e.zlevel] = true;

            return this;
        };

        /**
         * 添加高亮层数据
         *
         * @param {Object} params 参数
         */
        Storage.prototype.addHover = function (params) {
            if ((params.rotation && Math.abs(params.rotation[0]) > 0.0001)
                || (params.position
                    && (Math.abs(params.position[0]) > 0.0001
                        || Math.abs(params.position[1]) > 0.0001))
                || (params.scale
                    && (Math.abs(params.scale[0] - 1) > 0.0001
                    || Math.abs(params.scale[1] - 1) > 0.0001))
            ) {
                params.__needTransform = true;
            }
            else {
                params.__needTransform = false;
            }

            this._hoverElements.push(params);
            return this;
        };

        /**
         * 删除高亮层数据
         */
        Storage.prototype.delHover = function () {
            this._hoverElements = [];
            return this;
        };

        Storage.prototype.hasHoverShape = function () {
            return this._hoverElements.length > 0;
        };

        /**
         * 添加
         *
         * @param {Object} params 参数
         */
        Storage.prototype.add = function (params) {
            // 默认&必须的参数
            var e = {
                'shape': 'circle',                      // 形状
                'id': params.id || newShapeId(),   // 唯一标识
                'zlevel': 0,                            // z轴位置
                'draggable': false,                     // draggable可拖拽
                'clickable': false,                     // clickable可点击响应
                'hoverable': true,                      // hoverable可悬浮响应
                'position': [0, 0],
                'rotation' : [0, 0, 0],
                'scale' : [1, 1, 0, 0]
            };
            util.merge(
                e,
                params,
                {
                    'overwrite': true,
                    'recursive': true
                }
            );
            mark(e);
            this._elements[e.id] = e;
            this._zElements[e.zlevel] = this._zElements[e.zlevel] || [];
            this._zElements[e.zlevel].push(e);

            this._maxZlevel = Math.max(this._maxZlevel, e.zlevel);
            this._changedZlevel[e.zlevel] = true;

            return this;
        };

        /**
         * 根据指定的shapeId获取相应的shape属性
         *
         * @param {string=} idx 唯一标识
         */
        Storage.prototype.get = function (shapeId) {
            return this._elements[shapeId];
        };

        /**
         * 删除，shapeId不指定则全清空
         *
         * @param {string= | Array} idx 唯一标识
         */
        Storage.prototype.del = function (shapeId) {
            if (typeof shapeId != 'undefined') {
                var delMap = {};
                if (!(shapeId instanceof Array)) {
                    // 单个
                    delMap[shapeId] = true;
                }
                else {
                    // 批量删除
                    if (shapeId.lenth < 1) { // 空数组
                        return;
                    }
                    for (var i = 0, l = shapeId.length; i < l; i++) {
                        delMap[shapeId[i].id] = true;
                    }
                }
                var newList;
                var oldList;
                var zlevel;
                var zChanged = {};
                for (var sId in delMap) {
                    if (this._elements[sId]) {
                        zlevel = _elements[sId].zlevel;
                        this._changedZlevel[zlevel] = true;
                        if (!zChanged[zlevel]) {
                            oldList = this._zElements[zlevel];
                            newList = [];
                            for (var i = 0, l = oldList.length; i < l; i++){
                                if (!delMap[oldList[i].id]) {
                                    newList.push(oldList[i]);
                                }
                            }
                            this._zElements[zlevel] = newList;
                            zChanged[zlevel] = true;
                        }

                        delete this._elements[sId];
                    }
                }
            }
            else{
                // 不指定shapeId清空
                this._elements = {};
                this._zElements = [];
                this._hoverElements = [];
                this._maxZlevel = 0;         //最大zlevel
                this._changedZlevel = {      //有数据改变的zlevel
                    all : true
                };
            }

            return this;
        };

        Storage.prototype.getMaxZlevel = function () {
            return this._maxZlevel;
        };

        Storage.prototype.getChangedZlevel = function () {
            return this._changedZlevel;
        };

        Storage.prototype.clearChangedZlevel = function () {
            this._changedZlevel = {};
            return this;
        };

        Storage.prototype.setChangedZlevle = function (level) {
            this._changedZlevel[level] = true;
            return this;
        };

        /**
         * 释放
         */
        Storage.prototype.dispose = function () {
            this._elements = null;
            this._zElements = null;
            this._hoverElements = null;
        };

        Storage.prototype.newShapeId = newShapeId;

        return Storage;
    }
);
<|endoftext|>


<commit_before>'use strict';

(function () {
    CKEDITOR.plugins.add( 'autocolorize', {
        lang: 'de,en',
        init: function(editor) {
            new Autocolorize(editor);
		},
    } );

    function Autocolorize( editor, callback, throttle ) {
        this.editor = editor;
        this.active1 = false;
        this.active2 = false;
        var $this = this;

        editor.addCommand('toggleAdminTyped1', {
            requiredContent: 'li',
            exec: function (editor) { $this.toggleAdminTyped1(editor); }
        });
        editor.ui.addButton('ToggleAdminTyped1', {
            label: editor.lang.autocolorize.buttonTitle,
            command: 'toggleAdminTyped1',
            toolbar: 'autocolorize,100',
            icon: 'plugins/autocolorize/adminTyped1.png'
        });
        this.setActiveState1();

        editor.addCommand('toggleAdminTyped2', {
            requiredContent: 'li',
            exec: function (editor) { $this.toggleAdminTyped2(editor); }
        });
        editor.ui.addButton('ToggleAdminTyped2', {
            label: editor.lang.autocolorize.buttonTitle,
            command: 'toggleAdminTyped2',
            toolbar: 'autocolorize,100',
            icon: 'plugins/autocolorize/adminTyped2.png'
        });
        this.setActiveState2();

        if (this.editor.status === 'ready') {
            this.attach();
        } else {
            this.editor.on('instanceReady', function () {
                this.attach();
            }, this);
        }
    }

    Autocolorize.prototype = {
        attach: function() {
            var $this = this;
            this.editable = this.editor.editable();
            // this.editor.on("insertHtml", function (ev) { $this.onInsertHtml(ev); });
            // this.editor.on("insertText", function (ev) { $this.onInsertText(ev); });
            this.editable.on("keypress", function (ev) { $this.onKeyPress(ev); });
            // this.editable.on("keyup", function (ev) { $this.onKeyUp(ev); });
        },

        onInsertText: function (ev) {
            // console.log("onInsertText", ev.data);
        },

        onInsertHtml: function (ev) {
            // console.log("onInsertHtml", ev.data);
        },

        needsInsertingNode: function (element, adminTypedNo) {
            if (!element) {
                // Root element => no insert/delete / adminTyped element found => inserting is necessary
                return true;
            }
            if (element.nodeType === 3) {
                // Text node
                return this.needsInsertingNode(element.parentElement, adminTypedNo);
            }
            if (element.nodeType !== 1) {
                console.warn('Unexpected node type', element);
                return false;
            }

            if (element.nodeName === 'SPAN' && element.classList.contains('adminTyped' + adminTypedNo)) {
                return false;
            }
            if (element.nodeName === 'INS' || element.nodeName === 'DEL') {
                return false;
            }
            if (element.classList.contains('inserted') || element.classList.contains('deleted')) {
                return false;
            }

            return this.needsInsertingNode(element.parentElement, adminTypedNo);
        },

        insertNodeIfNecessary: function (ranges, ev, adminTypeNo) {
            if (!this.needsInsertingNode(ranges[0].startContainer.$, adminTypeNo)) {
                return;
            }
            ev.cancel();
            ev.data.preventDefault();
            let code = ev.data.$.key;
            if (code === ' ') {
                code = ' ';
            } else {
                code = CKEDITOR.tools.htmlEncode(ev.data.$.key);
            }
            this.editor.insertHtml('' + code + '', 'html');
            //this.editor.fire( 'saveSnapshot' );
        },

        onKeyPress: function (ev) {
            //this.editor.fire( 'saveSnapshot' );
            if (!this.active1 && !this.active2) {
                return;
            }

            var ranges = this.editor.getSelection().getRanges();
            if (ranges.length !== 1) {
                console.warn("strange selection", ranges);
                return;
            }
            if (this.active1) {
                this.insertNodeIfNecessary(ranges, ev, '1');
            }
            if (this.active2) {
                this.insertNodeIfNecessary(ranges, ev, '2');
            }
        },

        onKeyUp: function (ev) {
        },

        close: function() {

		},

        toggleAdminTyped1: function(editor) {
            this.active1 = !this.active1;
            this.setActiveState1();
        },

        setActiveState1() {
            if (this.active1) {
                this.editor.getCommand( 'toggleAdminTyped1' ).setState( CKEDITOR.TRISTATE_ON );
                this.editor.getCommand( 'toggleAdminTyped2' ).setState( CKEDITOR.TRISTATE_OFF );
                this.active2 = false;
            } else {
                this.editor.getCommand( 'toggleAdminTyped1' ).setState( CKEDITOR.TRISTATE_OFF );
            }
        },

        toggleAdminTyped2: function(editor) {
            this.active2 = !this.active2;
            this.setActiveState2();
        },

        setActiveState2() {
            if (this.active2) {
                this.editor.getCommand( 'toggleAdminTyped2' ).setState( CKEDITOR.TRISTATE_ON );
                this.editor.getCommand( 'toggleAdminTyped1' ).setState( CKEDITOR.TRISTATE_OFF );
                this.active1 = false;
            } else {
                this.editor.getCommand( 'toggleAdminTyped2' ).setState( CKEDITOR.TRISTATE_OFF );
            }
        },
    };

    CKEDITOR.plugins.autocolorize = Autocolorize;
})();
<commit_msg>Simplify autocolorize plugin<commit_after>'use strict';

(function () {
    CKEDITOR.plugins.add( 'autocolorize', {
        lang: 'de,en',
        init: function(editor) {
            this.initColor1(editor);
            this.initColor2(editor);
        },

        initColor1: function(editor) {
            var style = new CKEDITOR.style( {
                element: 'span',
                attributes: { 'class': 'adminTyped1' },
            } );

            // Listen to contextual style activation.
            editor.attachStyleStateChange( style, function( state ) {
                !editor.readOnly && editor.getCommand( 'toggleAdminTyped1' ).setState( state );
            } );

            // Create the command that can be used to apply the style.
            editor.addCommand( 'toggleAdminTyped1', new CKEDITOR.styleCommand( style) );

            editor.ui.addButton( 'ToggleAdminTyped1', {
                isToggle: true,
                label: editor.lang.autocolorize.buttonTitle,
                command: 'toggleAdminTyped1',
                toolbar: 'autocolorize,100',
                icon: 'plugins/autocolorize/adminTyped1.png'
            } );
        },

        initColor2: function(editor) {
            var style = new CKEDITOR.style({
                element: 'span',
                attributes: {'class': 'adminTyped2'},
            });

            // Listen to contextual style activation.
            editor.attachStyleStateChange(style, function (state) {
                !editor.readOnly && editor.getCommand('toggleAdminTyped2').setState(state);
            });

            // Create the command that can be used to apply the style.
            editor.addCommand('toggleAdminTyped2', new CKEDITOR.styleCommand(style));

            editor.ui.addButton('ToggleAdminTyped2', {
                isToggle: true,
                label: editor.lang.autocolorize.buttonTitle,
                command: 'toggleAdminTyped2',
                toolbar: 'autocolorize,100',
                icon: 'plugins/autocolorize/adminTyped2.png'
            });
        }
    } );
})();
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import { get } from 'lodash/object'
import fetchWikipediaResults from 'js/components/Search/fetchWikipediaResults'
import WikipediaPage from 'js/components/Search/WikipediaPageComponent'

class WikipediaQuery extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      queryInProgress: false,
      responseData: null,
    }
  }

  componentDidMount() {
    this.queryWikipedia()
  }

  componentDidUpdate(prevProps) {
    // Fetch Wikipedia data if a query exists and has changed.
    if (this.props.query && this.props.query !== prevProps.query) {
      this.queryWikipedia()
    }
  }

  async queryWikipedia() {
    const { query } = this.props
    if (!query) {
      return
    }
    this.setState({
      queryInProgress: true,
    })
    console.log(`Querying Wikipedia with query ${query}`)
    const results = await fetchWikipediaResults(query)
    this.setState({
      responseData: results,
      queryInProgress: false,
    })
  }

  render() {
    const { responseData, queryInProgress } = this.state
    const pageData = get(responseData, 'query.pages[0]')
    if (queryInProgress) {
      return null
    }
    if (!pageData) {
      return
Nothing found

    }
    // console.log(pageData)
    const {
      title,
      description,
      extract,
      fullurl: pageURL,
      thumbnail: { source: thumbnailURL } = {},
    } = pageData

    // TODO: sanitize the extract HTML
    return (
      <WikipediaPage
        title={title}
        description={description}
        thumbnailURL={thumbnailURL}
        extract={extract}
        pageURL={pageURL}
      />
    )
  }
}

WikipediaQuery.propTypes = {
  query: PropTypes.string.isRequired,
}

WikipediaQuery.defaultProps = {}

export default WikipediaQuery
<commit_msg>Sanitize Wikipedia HTML<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import { get } from 'lodash/object'
import sanitizeHtml from 'sanitize-html'
import fetchWikipediaResults from 'js/components/Search/fetchWikipediaResults'
import WikipediaPage from 'js/components/Search/WikipediaPageComponent'

class WikipediaQuery extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      queryInProgress: false,
      responseData: null,
    }
  }

  componentDidMount() {
    this.queryWikipedia()
  }

  componentDidUpdate(prevProps) {
    // Fetch Wikipedia data if a query exists and has changed.
    if (this.props.query && this.props.query !== prevProps.query) {
      this.queryWikipedia()
    }
  }

  async queryWikipedia() {
    const { query } = this.props
    if (!query) {
      return
    }
    this.setState({
      queryInProgress: true,
    })
    console.log(`Querying Wikipedia with query ${query}`)
    const results = await fetchWikipediaResults(query)
    this.setState({
      responseData: results,
      queryInProgress: false,
    })
  }

  render() {
    const { responseData, queryInProgress } = this.state
    const pageData = get(responseData, 'query.pages[0]')
    if (queryInProgress) {
      return null
    }
    if (!pageData) {
      return
Nothing found

    }
    // console.log(pageData)
    const {
      title,
      description,
      extract,
      fullurl: pageURL,
      thumbnail: { source: thumbnailURL } = {},
    } = pageData

    // Sanitize the HTML returned by Wikipedia.
    const extractSanitized = sanitizeHtml(extract, {
      allowedTags: [
        'h3',
        'h4',
        'h5',
        'h6',
        'blockquote',
        'p',
        'ul',
        'ol',
        'nl',
        'li',
        'b',
        'i',
        'strong',
        'em',
        'strike',
        'code',
        'hr',
        'br',
        'div',
        'table',
        'thead',
        'caption',
        'small',
      ],
      allowedAttributes: false,
    })
    return (
      <WikipediaPage
        title={title}
        description={description}
        thumbnailURL={thumbnailURL}
        extract={extractSanitized}
        pageURL={pageURL}
      />
    )
  }
}

WikipediaQuery.propTypes = {
  query: PropTypes.string.isRequired,
}

WikipediaQuery.defaultProps = {}

export default WikipediaQuery
<|endoftext|>


<commit_before>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // Add submenu class if present
        if ( $('.banner #sub-nav').length ) {
          $('body').addClass('has-sub');
        }
        // Minimize Header when scrolling
        var headerHeight = $('.banner').outerHeight();
        // Window load neccessary for accurate doc height
        $(window).load(function() {
          if ( $(window).height() + headerHeight < $(document).height() ) {
            $(window).scroll(function() {
              if( $(window).scrollTop() > 0) {
                $('body').addClass('mini');
              } else {
                $('body').removeClass('mini');
              }
            });
          }
        });
        // Searchfield
        $('.search-form__top-nav .toggle-search').click(function(e) {
          e.preventDefault();
          $(this).toggleClass('search-on');
          $('.search-form__top-nav .search-field').animate({width: 'toggle'}, 'fast', function() {
            $('.search-form__top-nav .search-field').focus();
            $('.search-form__top-nav .search-field').keypress(function(e) {
              if (e.which === 13) {
                e.preventDefault();
                $('.search-form__top-nav').submit();
              }
            });
            $('.search-form__top-nav .toggle-search').click(function(e) {
              e.preventDefault();
            });
          });
        });
        // Read More Link
        var $more_link = $('.split_more_link a.read-more');
        var more_text  = $more_link.html();
        $more_link.click(function(e){
          var less_text  = $(this).data('text-less');
          $(this).parents().find('.content_more').slideToggle('fast');
          $(this).html( $(this).html() === more_text ? less_text : more_text);
          $(this).toggleClass('less');
        });
        // Hover touch effects
        if (Modernizr.touch) {
          $('.touch_effect').click(function(e){
            if (!$(this).hasClass('hover')) {
              $(this).addClass('hover');
            }
          });
        } else {
          $('.touch_effect').mouseenter(function(){
            $(this).addClass('hover');
          })
          .mouseleave(function(){
            $(this).removeClass('hover');
          });
        }
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
        $('.owl-carousel').owlCarousel({
          animateOut:         "fadeOut",
          animateIn:          "fadeIn",
          items:              1,
          loop:               true,
          margin:             0,
          nav:                true,
          navText:            ['', ''],
          dots:               true,
          dotsContainer:      '.dots-nav .dots',
          autoplay:           true
        });
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'about_us': {
      init: function() {
        // JavaScript to be fired on the about us page
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.
<commit_msg>Add sticky footer<commit_after>/* ========================================================================
 * DOM-based Routing
 * Based on http://goo.gl/EUTi53 by Paul Irish
 *
 * Only fires on body classes that match. If a body class contains a dash,
 * replace the dash with an underscore when adding it to the object below.
 *
 * .noConflict()
 * The routing is enclosed within an anonymous function so that you can
 * always reference jQuery with $, even when in .noConflict() mode.
 * ======================================================================== */

(function($) {

  // Use this variable to set up the common and page specific functions. If you
  // rename this variable, you will also need to rename the namespace below.
  var Sage = {
    // All pages
    'common': {
      init: function() {
        // Add submenu class if present
        if ( $('.banner #sub-nav').length ) {
          $('body').addClass('has-sub');
        }
        // Minimize Header when scrolling
        var headerHeight = $('.banner').outerHeight();
        // Window load neccessary for accurate doc height
        $(window).load(function() {
          if ( $(window).height() + headerHeight < $(document).height() ) {
            $(window).scroll(function() {
              if( $(window).scrollTop() > 0) {
                $('body').addClass('mini');
              } else {
                $('body').removeClass('mini');
              }
            });
          }
        });
        // Searchfield
        $('.search-form__top-nav .toggle-search').click(function(e) {
          e.preventDefault();
          $(this).toggleClass('search-on');
          $('.search-form__top-nav .search-field').animate({width: 'toggle'}, 'fast', function() {
            $('.search-form__top-nav .search-field').focus();
            $('.search-form__top-nav .search-field').keypress(function(e) {
              if (e.which === 13) {
                e.preventDefault();
                $('.search-form__top-nav').submit();
              }
            });
            $('.search-form__top-nav .toggle-search').click(function(e) {
              e.preventDefault();
            });
          });
        });
        // Read More Link
        var $more_link = $('.split_more_link a.read-more');
        var more_text  = $more_link.html();
        $more_link.click(function(e){
          var less_text  = $(this).data('text-less');
          $(this).parents().find('.content_more').slideToggle('fast');
          $(this).html( $(this).html() === more_text ? less_text : more_text);
          $(this).toggleClass('less');
        });
        // Hover touch effects
        if (Modernizr.touch) {
          $('.touch_effect').click(function(e){
            if (!$(this).hasClass('hover')) {
              $(this).addClass('hover');
            }
          });
        } else {
          $('.touch_effect').mouseenter(function(){
            $(this).addClass('hover');
          })
          .mouseleave(function(){
            $(this).removeClass('hover');
          });
        }
        $.StickyFooter();
      },
      finalize: function() {
        // JavaScript to be fired on all pages, after page specific JS is fired
      }
    },
    // Home page
    'home': {
      init: function() {
        // JavaScript to be fired on the home page
        $('.owl-carousel').owlCarousel({
          animateOut:         "fadeOut",
          animateIn:          "fadeIn",
          items:              1,
          loop:               true,
          margin:             0,
          nav:                true,
          navText:            ['', ''],
          dots:               true,
          dotsContainer:      '.dots-nav .dots',
          autoplay:           true
        });
      },
      finalize: function() {
        // JavaScript to be fired on the home page, after the init JS
      }
    },
    // About us page, note the change from about-us to about_us.
    'about_us': {
      init: function() {
        // JavaScript to be fired on the about us page
      }
    }
  };

  // Sticky Footer
  $.StickyFooter = function() {
    StickyFooter.init();
  };
  var StickyFooter = {
    init: function() {
      $footer = $('.content-info');
      var fh = $footer.outerHeight();
      var ft = ($(window).scrollTop() + $(window).height() - fh)+"px";
      StickyFooter.sticky($footer, fh, ft);
      $(window).resize(function() {
        StickyFooter.sticky($footer, fh, ft);
      });
      $(window).scroll(function() {
        StickyFooter.sticky($footer, fh, ft);
      });
    },
    sticky : function($footer, fh, ft) {
      if ( ($(document.body).height() + fh) < $(window).height()) {
        $footer.css({
          position: "absolute",
          top:      ft,
          left:     0,
          right:    0
        });
      } else {
        $footer.css({
          position: "static"
        });
      }
    }
  };

  // The routing fires all common scripts, followed by the page specific scripts.
  // Add additional events for more control over timing e.g. a finalize event
  var UTIL = {
    fire: function(func, funcname, args) {
      var fire;
      var namespace = Sage;
      funcname = (funcname === undefined) ? 'init' : funcname;
      fire = func !== '';
      fire = fire && namespace[func];
      fire = fire && typeof namespace[func][funcname] === 'function';

      if (fire) {
        namespace[func][funcname](args);
      }
    },
    loadEvents: function() {
      // Fire common init JS
      UTIL.fire('common');

      // Fire page-specific init JS, and then finalize JS
      $.each(document.body.className.replace(/-/g, '_').split(/\s+/), function(i, classnm) {
        UTIL.fire(classnm);
        UTIL.fire(classnm, 'finalize');
      });

      // Fire common finalize JS
      UTIL.fire('common', 'finalize');
    }
  };

  // Load Events
  $(document).ready(UTIL.loadEvents);

})(jQuery); // Fully reference jQuery after this point.
<|endoftext|>