<commit_before>const subManager = new SubsManager();
const { calculateIndex, enableClickOnTouch } = Utils;

Template.boardListHeaderBar.events({
  'click .js-open-archived-board'() {
    Modal.open('archivedBoards');
  },
});

Template.boardListHeaderBar.helpers({
  title() {
    return FlowRouter.getRouteName() === 'home' ? 'my-boards' : 'public';
  },
  templatesBoardId() {
    return Meteor.user() && Meteor.user().getTemplatesBoardId();
  },
  templatesBoardSlug() {
    return Meteor.user() && Meteor.user().getTemplatesBoardSlug();
  },
});

BlazeComponent.extendComponent({
  onCreated() {
    Meteor.subscribe('setting');
  },

  onRendered() {
    const itemsSelector = '.js-board:not(.placeholder)';

    const $boards = this.$('.js-boards');
    $boards.sortable({
      connectWith: '.js-boards',
      tolerance: 'pointer',
      appendTo: '.board-list',
      helper: 'clone',
      distance: 7,
      items: itemsSelector,
      placeholder: 'board-wrapper placeholder',
      start(evt, ui) {
        ui.helper.css('z-index', 1000);
        ui.placeholder.height(ui.helper.height());
        EscapeActions.executeUpTo('popup-close');
      },
      stop(evt, ui) {
        // To attribute the new index number, we need to get the DOM element
        // of the previous and the following card -- if any.
        const prevBoardDom = ui.item.prev('.js-board').get(0);
        const nextBoardBom = ui.item.next('.js-board').get(0);
        const sortIndex = calculateIndex(prevBoardDom, nextBoardBom, 1);

        const boardDomElement = ui.item.get(0);
        const board = Blaze.getData(boardDomElement);
        // Normally the jquery-ui sortable library moves the dragged DOM element
        // to its new position, which disrupts Blaze reactive updates mechanism
        // (especially when we move the last card of a list, or when multiple
        // users move some cards at the same time). To prevent these UX glitches
        // we ask sortable to gracefully cancel the move, and to put back the
        // DOM in its initial state. The card move is then handled reactively by
        // Blaze with the below query.
        $boards.sortable('cancel');

        board.move(sortIndex.base);
      },
    });

    // ugly touch event hotfix
    enableClickOnTouch(itemsSelector);

    // Disable drag-dropping if the current user is not a board member or is comment only
    this.autorun(() => {
      if (Utils.isMiniScreen()) {
        $boards.sortable({
          handle: '.board-handle',
        });
      }
    });
  },

  boards() {
    const query = {
      archived: false,
      type: 'board',
    };
    if (FlowRouter.getRouteName() === 'home')
      query['members.userId'] = Meteor.userId();
    else query.permission = 'public';

    return Boards.find(query, {
      sort: { sort: 1 /* boards default sorting */ },
    });
  },
  isStarred() {
    const user = Meteor.user();
    return user && user.hasStarred(this.currentData()._id);
  },
  isAdministrable() {
    const user = Meteor.user();
    return user && user.isBoardAdmin(this.currentData()._id);
  },

  hasOvertimeCards() {
    subManager.subscribe('board', this.currentData()._id, false);
    return this.currentData().hasOvertimeCards();
  },

  hasSpentTimeCards() {
    subManager.subscribe('board', this.currentData()._id, false);
    return this.currentData().hasSpentTimeCards();
  },

  isInvited() {
    const user = Meteor.user();
    return user && user.isInvitedTo(this.currentData()._id);
  },

  events() {
    return [
      {
        'click .js-add-board': Popup.open('createBoard'),
        'click .js-star-board'(evt) {
          const boardId = this.currentData()._id;
          Meteor.user().toggleBoardStar(boardId);
          evt.preventDefault();
        },
        'click .js-clone-board'(evt) {
          Meteor.call(
            'copyBoard',
            this.currentData()._id,
            {
              sort: Boards.find({ archived: false }).count(),
              type: 'board',
              title: Boards.findOne(this.currentData()._id).title,
            },
            (err, res) => {
              if (err) {
                this.setError(err.error);
              } else {
                Session.set('fromBoard', null);
                Utils.goBoardId(res);
              }
            },
          );
          evt.preventDefault();
        },
        'click .js-archive-board'(evt) {
          const boardId = this.currentData()._id;
          Meteor.call('archiveBoard', boardId);
          evt.preventDefault();
        },
        'click .js-accept-invite'() {
          const boardId = this.currentData()._id;
          Meteor.call('acceptInvite', boardId);
        },
        'click .js-decline-invite'() {
          const boardId = this.currentData()._id;
          Meteor.call('quitBoard', boardId, (err, ret) => {
            if (!err && ret) {
              Meteor.call('acceptInvite', boardId);
              FlowRouter.go('home');
            }
          });
        },
      },
    ];
  },
}).register('boardList');
<commit_msg>Fix bug #3832 'Default language is still used although this one has been modified previously'<commit_after>const subManager = new SubsManager();
const { calculateIndex, enableClickOnTouch } = Utils;

Template.boardListHeaderBar.events({
  'click .js-open-archived-board'() {
    Modal.open('archivedBoards');
  },
});

Template.boardListHeaderBar.helpers({
  title() {
    return FlowRouter.getRouteName() === 'home' ? 'my-boards' : 'public';
  },
  templatesBoardId() {
    return Meteor.user() && Meteor.user().getTemplatesBoardId();
  },
  templatesBoardSlug() {
    return Meteor.user() && Meteor.user().getTemplatesBoardSlug();
  },
});

BlazeComponent.extendComponent({
  onCreated() {
    Meteor.subscribe('setting');
    let currUser = Meteor.user();
    let userLanguage;
    if(currUser && currUser.profile){
      userLanguage = currUser.profile.language
    }
    if (userLanguage) {
      TAPi18n.setLanguage(userLanguage);
      T9n.setLanguage(userLanguage);
    }
  },

  onRendered() {
    const itemsSelector = '.js-board:not(.placeholder)';

    const $boards = this.$('.js-boards');
    $boards.sortable({
      connectWith: '.js-boards',
      tolerance: 'pointer',
      appendTo: '.board-list',
      helper: 'clone',
      distance: 7,
      items: itemsSelector,
      placeholder: 'board-wrapper placeholder',
      start(evt, ui) {
        ui.helper.css('z-index', 1000);
        ui.placeholder.height(ui.helper.height());
        EscapeActions.executeUpTo('popup-close');
      },
      stop(evt, ui) {
        // To attribute the new index number, we need to get the DOM element
        // of the previous and the following card -- if any.
        const prevBoardDom = ui.item.prev('.js-board').get(0);
        const nextBoardBom = ui.item.next('.js-board').get(0);
        const sortIndex = calculateIndex(prevBoardDom, nextBoardBom, 1);

        const boardDomElement = ui.item.get(0);
        const board = Blaze.getData(boardDomElement);
        // Normally the jquery-ui sortable library moves the dragged DOM element
        // to its new position, which disrupts Blaze reactive updates mechanism
        // (especially when we move the last card of a list, or when multiple
        // users move some cards at the same time). To prevent these UX glitches
        // we ask sortable to gracefully cancel the move, and to put back the
        // DOM in its initial state. The card move is then handled reactively by
        // Blaze with the below query.
        $boards.sortable('cancel');

        board.move(sortIndex.base);
      },
    });

    // ugly touch event hotfix
    enableClickOnTouch(itemsSelector);

    // Disable drag-dropping if the current user is not a board member or is comment only
    this.autorun(() => {
      if (Utils.isMiniScreen()) {
        $boards.sortable({
          handle: '.board-handle',
        });
      }
    });
  },

  boards() {
    const query = {
      archived: false,
      type: 'board',
    };
    if (FlowRouter.getRouteName() === 'home')
      query['members.userId'] = Meteor.userId();
    else query.permission = 'public';

    return Boards.find(query, {
      sort: { sort: 1 /* boards default sorting */ },
    });
  },
  isStarred() {
    const user = Meteor.user();
    return user && user.hasStarred(this.currentData()._id);
  },
  isAdministrable() {
    const user = Meteor.user();
    return user && user.isBoardAdmin(this.currentData()._id);
  },

  hasOvertimeCards() {
    subManager.subscribe('board', this.currentData()._id, false);
    return this.currentData().hasOvertimeCards();
  },

  hasSpentTimeCards() {
    subManager.subscribe('board', this.currentData()._id, false);
    return this.currentData().hasSpentTimeCards();
  },

  isInvited() {
    const user = Meteor.user();
    return user && user.isInvitedTo(this.currentData()._id);
  },

  events() {
    return [
      {
        'click .js-add-board': Popup.open('createBoard'),
        'click .js-star-board'(evt) {
          const boardId = this.currentData()._id;
          Meteor.user().toggleBoardStar(boardId);
          evt.preventDefault();
        },
        'click .js-clone-board'(evt) {
          Meteor.call(
            'copyBoard',
            this.currentData()._id,
            {
              sort: Boards.find({ archived: false }).count(),
              type: 'board',
              title: Boards.findOne(this.currentData()._id).title,
            },
            (err, res) => {
              if (err) {
                this.setError(err.error);
              } else {
                Session.set('fromBoard', null);
                Utils.goBoardId(res);
              }
            },
          );
          evt.preventDefault();
        },
        'click .js-archive-board'(evt) {
          const boardId = this.currentData()._id;
          Meteor.call('archiveBoard', boardId);
          evt.preventDefault();
        },
        'click .js-accept-invite'() {
          const boardId = this.currentData()._id;
          Meteor.call('acceptInvite', boardId);
        },
        'click .js-decline-invite'() {
          const boardId = this.currentData()._id;
          Meteor.call('quitBoard', boardId, (err, ret) => {
            if (!err && ret) {
              Meteor.call('acceptInvite', boardId);
              FlowRouter.go('home');
            }
          });
        },
      },
    ];
  },
}).register('boardList');
<|endoftext|>


<commit_before>const statehandler = new StateHandler();

class App {
    constructor() {
        this.navigation = new Navigation();
        this.buffers = [];
        this.loadingQuery = 0;
        this.render();
        this.navigation.addEventListener('search', query => {
            this.search(query);
        });
        statehandler.addEventListener('update', query => {
            this.search(query);
        });
        statehandler.init();
    }

    render() {
        this.elem = function () {
            var $$a = document.createElement('div');
            $$a.appendChildren(this.navigation.elem);
            $$a.appendChildren(this.resultContainer = function () {
                var $$d = document.createElement('div');
                $$d.setAttribute('class', 'results');
                return $$d;
            }.call(this));
            return $$a;
        }.call(this);
        this.buffers.forEach(buffer => this.insert(buffer));
    }

    search(query, sender, buffer, network, before, since) {
        this.clear();
        this.navigation.input.blur();
        this.navigation.historyView.resetNavigation();
        this.navigation.historyView.add(new HistoryElement(query));
        this.navigation.input.value = query;
        statehandler.replace(query, sender, buffer, network, before, since);
        if (query.trim() === '')
            return;
        this.loadingQuery++;
        const queryId = this.loadingQuery;
        load('web/search/', statehandler.parse()).then(result => {
            if (this.loadingQuery !== queryId)
                return;
            this.buffers = result.map(buffer => {
                return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map(msg => {
                    return new Context(new Message(msg.messageid, msg.time, msg.sender, msg.message));
                }));
            });
            this.buffers.forEach(buffer => this.insert(buffer));
        });
    }

    clear() {
        while (this.buffers.length) {
            const buffer = this.buffers.pop();
            this.resultContainer.removeChild(buffer.elem);
        }
    }

    clearAll() {
        this.clear();
        this.navigation.historyView.clear();
        statehandler.clear();
    }

    insert(buffer) {
        this.resultContainer.appendChild(buffer.elem);
        buffer.addEventListener('loadMore', () => this.bufferLoadMore(buffer));
    }

    bufferLoadMore(buffer) {
        if (buffer.loading)
            return;
        buffer.setLoading(true);
        const offset = buffer.count();
        console.log(offset);
        load('web/searchbuffer/', statehandler.parse({
            buffer: buffer.id,
            offset: offset
        })).then(result => {
            buffer.load(result);
            buffer.setLoading(false);
        });
    }
}

moment.locale(navigator.languages || navigator.language);
const app = new App();
document.body.insertBefore(app.elem, document.body.firstChild);<commit_msg>Fixed a minor UI bug<commit_after>const statehandler = new StateHandler();
class App {
    constructor() {
        this.navigation = new Navigation();
        this.buffers = [];
        this.loadingQuery = 0;
        this.render();
        this.navigation.addEventListener('search', query => {
            this.search(query);
        });
        statehandler.addEventListener('update', query => {
            this.search(query);
        });
        statehandler.init();
    }
    render() {
        this.elem = function () {
            var $$a = document.createElement('div');
            $$a.appendChildren(this.navigation.elem);
            $$a.appendChildren(this.resultContainer = function () {
                var $$d = document.createElement('div');
                $$d.setAttribute('class', 'results');
                return $$d;
            }.call(this));
            return $$a;
        }.call(this);
        this.buffers.forEach(buffer => this.insert(buffer));
    }
    search(query, sender, buffer, network, before, since) {
        this.clear();
        this.navigation.input.blur();
        this.navigation.historyView.resetNavigation();
        this.navigation.historyView.add(new HistoryElement(query));
        this.navigation.input.value = query;
        statehandler.replace(query, sender, buffer, network, before, since);
        if (query.trim() === '')
            return;
        this.loadingQuery++;
        const queryId = this.loadingQuery;
        load('web/search/', statehandler.parse()).then(result => {
            if (this.loadingQuery !== queryId)
                return;
            this.buffers = result.map(buffer => {
                return new Buffer(buffer.bufferid, buffer.buffername, buffer.networkname, buffer.hasmore, buffer.messages.map(msg => {
                    return new Context(new Message(msg.messageid, msg.time, msg.sender, msg.message));
                }));
            });
            this.buffers.forEach(buffer => this.insert(buffer));
        });
    }
    clear() {
        while (this.buffers.length) {
            const buffer = this.buffers.pop();
            this.resultContainer.removeChild(buffer.elem);
        }
    }
    clearAll() {
        this.clear();
        this.navigation.historyView.clear();
        statehandler.clear();
    }
    insert(buffer) {
        this.resultContainer.appendChild(buffer.elem);
        buffer.addEventListener('loadMore', () => this.bufferLoadMore(buffer));
    }
    bufferLoadMore(buffer) {
        if (buffer.loading)
            return;
        buffer.setLoading(true);
        const offset = buffer.count();
        console.log(offset);
        load('web/searchbuffer/', statehandler.parse({
            buffer: buffer.id,
            offset: offset
        })).then(result => {
            buffer.load(result);
            buffer.setLoading(false);
        });
    }
}
moment.locale(navigator.languages || navigator.language);
const app = new App();
document.body.insertBefore(app.elem, document.body.firstChild);<|endoftext|>


<commit_before>Template.attachmentsGalery.events({
  'click .js-add-attachment': Popup.open('cardAttachments'),
  'click .js-confirm-delete': Popup.afterConfirm(
    'attachmentDelete',
    function() {
      Attachments.remove(this._id);
      Popup.back();
    },
  ),
  // If we let this event bubble, FlowRouter will handle it and empty the page
  // content, see #101.
  'click .js-download'(event) {
    event.stopPropagation();
  },
  'click .js-add-cover'() {
    Cards.findOne(this.cardId).setCover(this._id);
  },
  'click .js-remove-cover'() {
    Cards.findOne(this.cardId).unsetCover();
  },
  'click .js-preview-image'(event) {
    Popup.open('previewAttachedImage').call(this, event);
    // when multiple thumbnails, if click one then another very fast,
    // we might get a wrong width from previous img.
    // when popup reused, onRendered() won't be called, so we cannot get there.
    // here make sure to get correct size when this img fully loaded.
    const img = $('img.preview-large-image')[0];
    if (!img) return;
    const rePosPopup = () => {
      const w = img.width;
      const h = img.height;
      // if the image is too large, we resize & center the popup.
      if (w > 300) {
        $('div.pop-over').css({
          width: w + 20,
          position: 'absolute',
          left: (window.innerWidth - w) / 2,
          top: (window.innerHeight - h) / 2,
        });
      }
    };
    const url = $(event.currentTarget).attr('src');
    if (img.src === url && img.complete) rePosPopup();
    else img.onload = rePosPopup;
  },
});

Template.attachmentsGalery.helpers({
  isBoardAdmin() {
    return Meteor.user().isBoardAdmin();
  },
  fileSize(size) {
    return Math.round(size / 1024);
  },
});

Template.previewAttachedImagePopup.events({
  'click .js-large-image-clicked'() {
    Popup.back();
  },
});

Template.cardAttachmentsPopup.events({
  'change .js-attach-file'(event) {
    const card = this;
    if (event.currentTarget.files && event.currentTarget.files[0]) {
      const uploader = Attachments.insert(
        {
          file: event.currentTarget.files[0],
          meta: Utils.getCommonAttachmentMetaFrom(card),
          chunkSize: 'dynamic',
        },
        false,
      );
      uploader.on('uploaded', (error, fileRef) => {
        if (!error) {
          if (fileRef.isImage) {
            card.setCover(fileRef._id);
          }
        }
      });
      uploader.on('end', (error, fileRef) => {
        Popup.back();
      });
      uploader.start();
    }
  },
  'click .js-computer-upload'(event, templateInstance) {
    templateInstance.find('.js-attach-file').click();
    event.preventDefault();
  },
  'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
});

const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
let pastedResults = null;

Template.previewClipboardImagePopup.onRendered(() => {
  // we can paste image from clipboard
  const handle = results => {
    if (results.dataURL.startsWith('data:image/')) {
      const direct = results => {
        $('img.preview-clipboard-image').attr('src', results.dataURL);
        pastedResults = results;
      };
      if (MAX_IMAGE_PIXEL) {
        // if has size limitation on image we shrink it before uploading
        Utils.shrinkImage({
          dataurl: results.dataURL,
          maxSize: MAX_IMAGE_PIXEL,
          ratio: COMPRESS_RATIO,
          callback(changed) {
            if (changed !== false && !!changed) {
              results.dataURL = changed;
            }
            direct(results);
          },
        });
      } else {
        direct(results);
      }
    }
  };

  $(document.body).pasteImageReader(handle);

  // we can also drag & drop image file to it
  $(document.body).dropImageReader(handle);
});

Template.previewClipboardImagePopup.events({
  'click .js-upload-pasted-image'() {
    const card = this;
    if (pastedResults && pastedResults.file) {
      const file = pastedResults.file;
      window.oPasted = pastedResults;
      const uploader = Attachments.insert(
        {
          file,
          meta: Utils.getCommonAttachmentMetaFrom(card),
          fileName: file.name || file.type.replace('image/', 'clipboard.'),
          chunkSize: 'dynamic',
        },
        false,
      );
      uploader.on('uploaded', (error, fileRef) => {
        if (!error) {
          if (fileRef.isImage) {
            card.setCover(fileRef._id);
          }
        }
      });
      uploader.on('end', (error, fileRef) => {
        pastedResults = null;
        $(document.body).pasteImageReader(() => {});
        Popup.back();
      });
      uploader.start();
    }
  },
});
<commit_msg>fixup! Ref: original & and use fileObj.meta<commit_after>Template.attachmentsGalery.events({
  'click .js-add-attachment': Popup.open('cardAttachments'),
  'click .js-confirm-delete': Popup.afterConfirm(
    'attachmentDelete',
    function() {
      Attachments.remove(this._id);
      Popup.back();
    },
  ),
  // If we let this event bubble, FlowRouter will handle it and empty the page
  // content, see #101.
  'click .js-download'(event) {
    event.stopPropagation();
  },
  'click .js-add-cover'() {
    Cards.findOne(this.meta.cardId).setCover(this._id);
  },
  'click .js-remove-cover'() {
    Cards.findOne(this.meta.cardId).unsetCover();
  },
  'click .js-preview-image'(event) {
    Popup.open('previewAttachedImage').call(this, event);
    // when multiple thumbnails, if click one then another very fast,
    // we might get a wrong width from previous img.
    // when popup reused, onRendered() won't be called, so we cannot get there.
    // here make sure to get correct size when this img fully loaded.
    const img = $('img.preview-large-image')[0];
    if (!img) return;
    const rePosPopup = () => {
      const w = img.width;
      const h = img.height;
      // if the image is too large, we resize & center the popup.
      if (w > 300) {
        $('div.pop-over').css({
          width: w + 20,
          position: 'absolute',
          left: (window.innerWidth - w) / 2,
          top: (window.innerHeight - h) / 2,
        });
      }
    };
    const url = $(event.currentTarget).attr('src');
    if (img.src === url && img.complete) rePosPopup();
    else img.onload = rePosPopup;
  },
});

Template.attachmentsGalery.helpers({
  isBoardAdmin() {
    return Meteor.user().isBoardAdmin();
  },
  fileSize(size) {
    return Math.round(size / 1024);
  },
});

Template.previewAttachedImagePopup.events({
  'click .js-large-image-clicked'() {
    Popup.back();
  },
});

Template.cardAttachmentsPopup.events({
  'change .js-attach-file'(event) {
    const card = this;
    if (event.currentTarget.files && event.currentTarget.files[0]) {
      const uploader = Attachments.insert(
        {
          file: event.currentTarget.files[0],
          meta: Utils.getCommonAttachmentMetaFrom(card),
          chunkSize: 'dynamic',
        },
        false,
      );
      uploader.on('uploaded', (error, fileRef) => {
        if (!error) {
          if (fileRef.isImage) {
            card.setCover(fileRef._id);
          }
        }
      });
      uploader.on('end', (error, fileRef) => {
        Popup.back();
      });
      uploader.start();
    }
  },
  'click .js-computer-upload'(event, templateInstance) {
    templateInstance.find('.js-attach-file').click();
    event.preventDefault();
  },
  'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
});

const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
let pastedResults = null;

Template.previewClipboardImagePopup.onRendered(() => {
  // we can paste image from clipboard
  const handle = results => {
    if (results.dataURL.startsWith('data:image/')) {
      const direct = results => {
        $('img.preview-clipboard-image').attr('src', results.dataURL);
        pastedResults = results;
      };
      if (MAX_IMAGE_PIXEL) {
        // if has size limitation on image we shrink it before uploading
        Utils.shrinkImage({
          dataurl: results.dataURL,
          maxSize: MAX_IMAGE_PIXEL,
          ratio: COMPRESS_RATIO,
          callback(changed) {
            if (changed !== false && !!changed) {
              results.dataURL = changed;
            }
            direct(results);
          },
        });
      } else {
        direct(results);
      }
    }
  };

  $(document.body).pasteImageReader(handle);

  // we can also drag & drop image file to it
  $(document.body).dropImageReader(handle);
});

Template.previewClipboardImagePopup.events({
  'click .js-upload-pasted-image'() {
    const card = this;
    if (pastedResults && pastedResults.file) {
      const file = pastedResults.file;
      window.oPasted = pastedResults;
      const uploader = Attachments.insert(
        {
          file,
          meta: Utils.getCommonAttachmentMetaFrom(card),
          fileName: file.name || file.type.replace('image/', 'clipboard.'),
          chunkSize: 'dynamic',
        },
        false,
      );
      uploader.on('uploaded', (error, fileRef) => {
        if (!error) {
          if (fileRef.isImage) {
            card.setCover(fileRef._id);
          }
        }
      });
      uploader.on('end', (error, fileRef) => {
        pastedResults = null;
        $(document.body).pasteImageReader(() => {});
        Popup.back();
      });
      uploader.start();
    }
  },
});
<|endoftext|>


<commit_before>Template.attachmentsGalery.events({
  'click .js-add-attachment': Popup.open('cardAttachments'),
  'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete',
    function() {
      Attachments.remove(this._id);
      Popup.close();
    }
  ),
  // If we let this event bubble, FlowRouter will handle it and empty the page
  // content, see #101.
  'click .js-download'(event) {
    event.stopPropagation();
  },
  'click .js-add-cover'() {
    Cards.findOne(this.cardId).setCover(this._id);
  },
  'click .js-remove-cover'() {
    Cards.findOne(this.cardId).unsetCover();
  },
  'click .js-preview-image'(evt) {
    Popup.open('previewAttachedImage').call(this, evt);
    // when multiple thumbnails, if click one then another very fast,
    // we might get a wrong width from previous img.
    // when popup reused, onRendered() won't be called, so we cannot get there.
    // here make sure to get correct size when this img fully loaded.
    const img = $('img.preview-large-image')[0];
    if (!img) return;
    const rePosPopup = () => {
      const w = img.width;
      const h = img.height;
      // if the image is too large, we resize & center the popup.
      if (w > 300) {
        $('div.pop-over').css({
          width: (w + 20),
          position: 'absolute',
          left: (window.innerWidth - w)/2,
          top: (window.innerHeight - h)/2,
        });
      }
    };
    const url = $(evt.currentTarget).attr('src');
    if (img.src === url && img.complete)
      rePosPopup();
    else
      img.onload = rePosPopup;
  },
});

Template.previewAttachedImagePopup.events({
  'click .js-large-image-clicked'(){
    Popup.close();
  },
});

Template.cardAttachmentsPopup.events({
  'change .js-attach-file'(evt) {
    const card = this;
    FS.Utility.eachFile(evt, (f) => {
      const file = new FS.File(f);
      if (card.isLinkedCard()) {
        file.boardId = Cards.findOne(card.linkedId).boardId;
        file.cardId = card.linkedId;
      } else {
        file.boardId = card.boardId;
        file.cardId = card._id;
      }
      file.userId = Meteor.userId();

      const attachment = Attachments.insert(file);

      if (attachment && attachment._id && attachment.isImage()) {
        card.setCover(attachment._id);
      }

      Popup.close();
    });
  },
  'click .js-computer-upload'(evt, tpl) {
    tpl.find('.js-attach-file').click();
    evt.preventDefault();
  },
  'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
});

let pastedResults = null;

Template.previewClipboardImagePopup.onRendered(() => {
  // we can paste image from clipboard
  $(document.body).pasteImageReader((results) => {
    if (results.dataURL.startsWith('data:image/')) {
      $('img.preview-clipboard-image').attr('src', results.dataURL);
      pastedResults = results;
    }
  });

  // we can also drag & drop image file to it
  $(document.body).dropImageReader((results) => {
    if (results.dataURL.startsWith('data:image/')) {
      $('img.preview-clipboard-image').attr('src', results.dataURL);
      pastedResults = results;
    }
  });
});

Template.previewClipboardImagePopup.events({
  'click .js-upload-pasted-image'() {
    const results = pastedResults;
    if (results && results.file) {
      const card = this;
      const file = new FS.File(results.file);
      if (!results.name) {
        // if no filename, it's from clipboard. then we give it a name, with ext name from MIME type
        if (typeof results.file.type === 'string') {
          file.name(results.file.type.replace('image/', 'clipboard.'));
        }
      }
      file.updatedAt(new Date());
      file.boardId = card.boardId;
      file.cardId = card._id;
      file.userId = Meteor.userId();
      const attachment = Attachments.insert(file);

      if (attachment && attachment._id && attachment.isImage()) {
        card.setCover(attachment._id);
      }

      pastedResults = null;
      $(document.body).pasteImageReader(() => {});
      Popup.close();
    }
  },
});
<commit_msg>Fix Attachment Outgoing Webhook missing list and swimlane name.<commit_after>Template.attachmentsGalery.events({
  'click .js-add-attachment': Popup.open('cardAttachments'),
  'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete',
    function() {
      Attachments.remove(this._id);
      Popup.close();
    }
  ),
  // If we let this event bubble, FlowRouter will handle it and empty the page
  // content, see #101.
  'click .js-download'(event) {
    event.stopPropagation();
  },
  'click .js-add-cover'() {
    Cards.findOne(this.cardId).setCover(this._id);
  },
  'click .js-remove-cover'() {
    Cards.findOne(this.cardId).unsetCover();
  },
  'click .js-preview-image'(evt) {
    Popup.open('previewAttachedImage').call(this, evt);
    // when multiple thumbnails, if click one then another very fast,
    // we might get a wrong width from previous img.
    // when popup reused, onRendered() won't be called, so we cannot get there.
    // here make sure to get correct size when this img fully loaded.
    const img = $('img.preview-large-image')[0];
    if (!img) return;
    const rePosPopup = () => {
      const w = img.width;
      const h = img.height;
      // if the image is too large, we resize & center the popup.
      if (w > 300) {
        $('div.pop-over').css({
          width: (w + 20),
          position: 'absolute',
          left: (window.innerWidth - w)/2,
          top: (window.innerHeight - h)/2,
        });
      }
    };
    const url = $(evt.currentTarget).attr('src');
    if (img.src === url && img.complete)
      rePosPopup();
    else
      img.onload = rePosPopup;
  },
});

Template.previewAttachedImagePopup.events({
  'click .js-large-image-clicked'(){
    Popup.close();
  },
});

Template.cardAttachmentsPopup.events({
  'change .js-attach-file'(evt) {
    const card = this;
    FS.Utility.eachFile(evt, (f) => {
      const file = new FS.File(f);
      if (card.isLinkedCard()) {
        file.boardId = Cards.findOne(card.linkedId).boardId;
        file.cardId = card.linkedId;
      } else {
        file.boardId = card.boardId;
        file.swimlaneId = card.swimlaneId;
        file.listId = card.listId;
        file.cardId = card._id;
      }
      file.userId = Meteor.userId();

      const attachment = Attachments.insert(file);

      if (attachment && attachment._id && attachment.isImage()) {
        card.setCover(attachment._id);
      }

      Popup.close();
    });
  },
  'click .js-computer-upload'(evt, tpl) {
    tpl.find('.js-attach-file').click();
    evt.preventDefault();
  },
  'click .js-upload-clipboard-image': Popup.open('previewClipboardImage'),
});

let pastedResults = null;

Template.previewClipboardImagePopup.onRendered(() => {
  // we can paste image from clipboard
  $(document.body).pasteImageReader((results) => {
    if (results.dataURL.startsWith('data:image/')) {
      $('img.preview-clipboard-image').attr('src', results.dataURL);
      pastedResults = results;
    }
  });

  // we can also drag & drop image file to it
  $(document.body).dropImageReader((results) => {
    if (results.dataURL.startsWith('data:image/')) {
      $('img.preview-clipboard-image').attr('src', results.dataURL);
      pastedResults = results;
    }
  });
});

Template.previewClipboardImagePopup.events({
  'click .js-upload-pasted-image'() {
    const results = pastedResults;
    if (results && results.file) {
      const card = this;
      const file = new FS.File(results.file);
      if (!results.name) {
        // if no filename, it's from clipboard. then we give it a name, with ext name from MIME type
        if (typeof results.file.type === 'string') {
          file.name(results.file.type.replace('image/', 'clipboard.'));
        }
      }
      file.updatedAt(new Date());
      file.boardId = card.boardId;
      file.cardId = card._id;
      file.userId = Meteor.userId();
      const attachment = Attachments.insert(file);

      if (attachment && attachment._id && attachment.isImage()) {
        card.setCover(attachment._id);
      }

      pastedResults = null;
      $(document.body).pasteImageReader(() => {});
      Popup.close();
    }
  },
});
<|endoftext|>


<commit_before>//import warning from 'warning'

function deprecate(fn, message) {
  return fn
  //return function () {
  //  warning(false, '[history] ' + message)
  //  return fn.apply(this, arguments)
  //}
}

export default deprecate
<commit_msg>Remove unused arg<commit_after>//import warning from 'warning'

function deprecate(fn) {
  return fn
  //return function () {
  //  warning(false, '[history] ' + message)
  //  return fn.apply(this, arguments)
  //}
}

export default deprecate
<|endoftext|>


<commit_before>var hasPushstate = !!(window.history && history.pushState);

var smallScreen = window.screen.width < 500;

//    Generate table of contents
var generateTOC = function() {

    $(".post-content").find('h1,h2,h3,h4')
        .each(function (i) {
            var current = $(this);
            current.attr("id", "title" + i);
            $("#toc").append("
" +
                current.text() + "
");
        });

};

//   Scroll spy headline

var scrollSpy = function(){
    for (var i = 1; i < 7; i++) {
        var headI = 'h' + i;
        $('#toc-content').text('Introduction');
        $('.post-content').find(headI).each(function () {
            var self = $(this);
            self.waypoint(function () {
                $('#navbar-toc').show();
                var tocText = self.text();
                $('#toc-content').text(tocText);
            }, {
                context: '.scroller',
                offset: 90
            });
        });
    };
};

//   Easter egg
var kaelEgg = new window.keypress.Listener();
function showEgg(){
    $('.block').remove();
    $('#egg-frame').fadeIn('slow');
    $('#close-button').fadeIn('slow');
    kaelEgg.reset();
}
var kaelEggCombo = kaelEgg.sequence_combo("q w e r", function() {
    lives = 0.8;
    $('.block').show();
    $('.egg').addClass('bounceIn').removeClass('bounceOut');
    $('.egg').append('');
//    iframe onload taken from http://www.nczonline.net/blog/2009/09/15/iframes-onload-and-documentdomain/
    var iframe = document.getElementById('egg-frame');
    if (iframe.attachEvent){
        iframe.attachEvent("onload", function(){
            showEgg();
        });
    } else {
        iframe.onload = function(){
            showEgg();
        };
    }
}, true);

$('#close-button').click(function(){
    $('.egg').removeClass('bounceIn').addClass('bounceOut');
    kaelEgg.register_combo(kaelEggCombo);
    return false;
});

//  Easter egg END

afterPjax();
function afterPjax() {

    postTitle = document.title;
    postHref = window.location.href;

    var ie = navigator.userAgent.match(/windows\snt\s([\d\.]+)/i);
    if (ie !== null && ie[1] < 6) {
        document.getElementsByTagName('html')[0].className += ' windows-xp';
    }

    //    Scroll-To-Top button take effect
    $("#scroll-up").click(function () {
        $(".scroller").animate({ scrollTop: "10" }, "350");
    });

    //  Mutil-push-menu init
    new mlPushMenu(document.getElementById('mp-menu'), document.getElementById('trigger'), {
        type: 'cover'
    });

    $('img').each( function() {
        var $img = $(this),
            href = $img.attr('src');
        $img.wrap('');
    });

    $('a[data-lightbox="a"]').fluidbox({
        stackIndex : 1
    });

    $('.share-button').popover({
        placement: 'bottom',
        content: '' +
            '' +
            '' +
            '' +
            '',
        html: true
    });

//    Fixed Multi-level-push-menu for PJAX
    $(".mp-pjax a").click(function (e) {
        e.preventDefault();
        e.stopPropagation();
        var pjaxHref = this.href;
        $('.scroller').trigger('click');
        if ( hasPushstate ) {
            $(".pjax-hidden a").each(function () {
                if (this.href === pjaxHref) {
                    $(this).trigger('click');
                }
            });
        }
    });

    $("a.back-home").click(function (e) {
        e.preventDefault();
        $('.scroller').trigger('click');
        $('#nexus-back').trigger('click');
    });

//  Some JS hacks

    $("a.fa-archive,a.fa-copy,a.fa-tags").click(function () {
        $(".fa-angle-left").css('opacity', '0');
    });
    $(".mp-back").click(function () {
        $(".fa-angle-left").css('opacity','1');
    });
//    Instant search init
    $('input.search-archive').quicksearch('li.search-archive-li');
    $('input.search-category').quicksearch('li.search-category-li');
    $('input.search-tag').quicksearch('li.search-tag-li');

//    Detect URL is Post page or NOT

    isPostPage = false;

    if (location.pathname === "/" || location.pathname.match("/tags/") !== null
        || location.pathname.match("/categories/") !== null ||
        location.pathname.match("/page/") !== null) {
        isPostPage = false;
    } else {
        isPostPage = true;
    }
//    Scroll 500px show Scroll-To-Top button
    $('.scroller').scroll(function () {
        var scroll2top = $('.scroller').scrollTop();
        if (scroll2top > 500) {
            $("#scroll-up").show();
        } else {
            $("#scroll-up").hide();
        }
    });

    $("#scroll-up").hide();

//    If no headline , hide the toc
    if ($('#toc').find('li').length === 0) {
        $('#navbar-toc').hide();
    }
//    Scroll 150px show full header
    if (isPostPage && !smallScreen) {
        generateTOC();
        setTimeout("scrollSpy()",300);

        $('.scroller').scroll(function () {
            if ((window.screen.width - 700)/2 > $('#trigger').parent().width() + $('#nexus-back').parent().width()){
                if ($('li#navbar-title').width() + $('li#navbar-toc').width() > $('.post').width()) {
                    $('li#navbar-title').hide();
                } else {
                    $('li#navbar-title').show();
                }
            } else {
                $('li#navbar-title').hide();
            }
            var scroll2top = $('.scroller').scrollTop();
            if (scroll2top > 150) {
                $('.nexus').css('width', '100%');
                $('.post-navbar').show(300);
                $('#navbar-title a').show();

            } else {
                $('.post-navbar').hide(300);
                $('.nexus').css('width', 'auto');
            }
        });
    }

//    Smooth Scroll for the TOC in header
    $('#toc a').click(function (e) {
        var headID = $(this).attr('href');
        var headIDpos = $(headID).position().top;
        $('.scroller').animate({ scrollTop: headIDpos + 200 }, 'linear');

        e.preventDefault();
    });

//    Hover TOC navbar to show
    $('#navbar-toc').hover(function () {
        $('#navbar-toc i').removeClass('hover-down').addClass("hover-up");
        $('.hidden-box').slideDown();
    }, function () {
        $('#navbar-toc i').removeClass('hover-up').addClass("hover-down");
        $('.hidden-box').slideUp();
    });

//    Reset Header
    if (isPostPage) {
        var headTitle = $('h1.post-title').text();
        $("#navbar-title a").text(headTitle);
    } else {
        $('.post-navbar').hide(300);
        $('.nexus').css('width', 'auto');
    }

};
//      PJAX init
$(document).pjax('a[data-pjax]', '.container', { fragment: '.container', timeout: 10000 });
$(document).on({
    'pjax:click': function () {
        $('.scroller').removeClass('fadeIn').addClass('fadeOut');
        NProgress.start();
    },
    'pjax:start': function () {
        $('.scroller').css('opacity','0');
    },
    'pjax:end': function () {
        NProgress.done();
        $('.scroller').css('opacity','1').removeClass('fadeOut').addClass('fadeIn');
        afterPjax();
        $('#navbar-toc').hide();
        $('.nexus').css('width', 'auto');
        $('#navbar-title a').hide();
    },
    'pjax:popstate': function () {
        setTimeout("$('#toc').find('li').remove();",100);
        setTimeout("generateTOC()",200);
        setTimeout("$('#comment-box').children().remove();",100);
    },
});

<commit_msg>Use click instead of hover to show hide TOC<commit_after>var hasPushstate = !!(window.history && history.pushState);

var smallScreen = window.screen.width < 500;

//    Generate table of contents
var generateTOC = function() {

    $(".post-content").find('h1,h2,h3,h4')
        .each(function (i) {
            var current = $(this);
            current.attr("id", "title" + i);
            $("#toc").append("
" +
                current.text() + "
");
        });

};

//   Scroll spy headline

var scrollSpy = function(){
    for (var i = 1; i < 7; i++) {
        var headI = 'h' + i;
        $('#toc-content').text('Introduction');
        $('.post-content').find(headI).each(function () {
            var self = $(this);
            self.waypoint(function () {
                $('#navbar-toc').show();
                var tocText = self.text();
                $('#toc-content').text(tocText);
            }, {
                context: '.scroller',
                offset: 90
            });
        });
    };
};

//   Easter egg
var kaelEgg = new window.keypress.Listener();
function showEgg(){
    $('.block').remove();
    $('#egg-frame').fadeIn('slow');
    $('#close-button').fadeIn('slow');
    kaelEgg.reset();
}
var kaelEggCombo = kaelEgg.sequence_combo("q w e r", function() {
    lives = 0.8;
    $('.block').show();
    $('.egg').addClass('bounceIn').removeClass('bounceOut');
    $('.egg').append('');
//    iframe onload taken from http://www.nczonline.net/blog/2009/09/15/iframes-onload-and-documentdomain/
    var iframe = document.getElementById('egg-frame');
    if (iframe.attachEvent){
        iframe.attachEvent("onload", function(){
            showEgg();
        });
    } else {
        iframe.onload = function(){
            showEgg();
        };
    }
}, true);

$('#close-button').click(function(){
    $('.egg').removeClass('bounceIn').addClass('bounceOut');
    kaelEgg.register_combo(kaelEggCombo);
    return false;
});

//  Easter egg END

afterPjax();
function afterPjax() {

    postTitle = document.title;
    postHref = window.location.href;

    var ie = navigator.userAgent.match(/windows\snt\s([\d\.]+)/i);
    if (ie !== null && ie[1] < 6) {
        document.getElementsByTagName('html')[0].className += ' windows-xp';
    }

    //    Scroll-To-Top button take effect
    $("#scroll-up").click(function () {
        $(".scroller").animate({ scrollTop: "10" }, "350");
    });

    //  Mutil-push-menu init
    new mlPushMenu(document.getElementById('mp-menu'), document.getElementById('trigger'), {
        type: 'cover'
    });

    $('img').each( function() {
        var $img = $(this),
            href = $img.attr('src');
        $img.wrap('');
    });

    $('a[data-lightbox="a"]').fluidbox({
        stackIndex : 1
    });

    $('.share-button').popover({
        placement: 'bottom',
        content: '' +
            '' +
            '' +
            '' +
            '',
        html: true
    });

//    Fixed Multi-level-push-menu for PJAX
    $(".mp-pjax a").click(function (e) {
        e.preventDefault();
        e.stopPropagation();
        var pjaxHref = this.href;
        $('.scroller').trigger('click');
        if ( hasPushstate ) {
            $(".pjax-hidden a").each(function () {
                if (this.href === pjaxHref) {
                    $(this).trigger('click');
                }
            });
        }
    });

    $("a.back-home").click(function (e) {
        e.preventDefault();
        $('.scroller').trigger('click');
        $('#nexus-back').trigger('click');
    });

//  Some JS hacks

    $("a.fa-archive,a.fa-copy,a.fa-tags").click(function () {
        $(".fa-angle-left").css('opacity', '0');
    });
    $(".mp-back").click(function () {
        $(".fa-angle-left").css('opacity','1');
    });
//    Instant search init
    $('input.search-archive').quicksearch('li.search-archive-li');
    $('input.search-category').quicksearch('li.search-category-li');
    $('input.search-tag').quicksearch('li.search-tag-li');

//    Detect URL is Post page or NOT

    isPostPage = false;

    if (location.pathname === "/" || location.pathname.match("/tags/") !== null
        || location.pathname.match("/categories/") !== null ||
        location.pathname.match("/page/") !== null) {
        isPostPage = false;
    } else {
        isPostPage = true;
    }
//    Scroll 500px show Scroll-To-Top button
    $('.scroller').scroll(function () {
        var scroll2top = $('.scroller').scrollTop();
        if (scroll2top > 500) {
            $("#scroll-up").show();
        } else {
            $("#scroll-up").hide();
        }
    });

    $("#scroll-up").hide();

//    If no headline , hide the toc
    if ($('#toc').find('li').length === 0) {
        $('#navbar-toc').hide();
    }
//    Scroll 150px show full header
    if (isPostPage && !smallScreen) {
        generateTOC();
        setTimeout("scrollSpy()",300);

        $('.scroller').scroll(function () {
            if ((window.screen.width - 700)/2 > $('#trigger').parent().width() + $('#nexus-back').parent().width()){
                if ($('li#navbar-title').width() + $('li#navbar-toc').width() > $('.post').width()) {
                    $('li#navbar-title').hide();
                } else {
                    $('li#navbar-title').show();
                }
            } else {
                $('li#navbar-title').hide();
            }
            var scroll2top = $('.scroller').scrollTop();
            if (scroll2top > 150) {
                $('.nexus').css('width', '100%');
                $('.post-navbar').show(300);
                $('#navbar-title a').show();

            } else {
                $('.post-navbar').hide(300);
                $('.nexus').css('width', 'auto');
            }
        });
    }

//    Smooth Scroll for the TOC in header
    $('#toc a').click(function (e) {
        var headID = $(this).attr('href');
        var headIDpos = $(headID).position().top;
        $('.scroller').animate({ scrollTop: headIDpos + 200 }, 'linear');

        e.preventDefault();
    });

//    Click TOC navbar to show or hide
    var isTocShow = false;
    $('#navbar-toc').click(function(e){
        if (!isTocShow) {
            $('#navbar-toc i').removeClass('hover-down').addClass("hover-up");
            $('.hidden-box').slideDown();
            isTocShow = true;
        } else {
            $('#navbar-toc i').removeClass('hover-up').addClass("hover-down");
            $('.hidden-box').slideUp();
            isTocShow = false;
        }
        e.prevent_default;
    })

//    Reset Header
    if (isPostPage) {
        var headTitle = $('h1.post-title').text();
        $("#navbar-title a").text(headTitle);
    } else {
        $('.post-navbar').hide(300);
        $('.nexus').css('width', 'auto');
    }

};
//      PJAX init
$(document).pjax('a[data-pjax]', '.container', { fragment: '.container', timeout: 10000 });
$(document).on({
    'pjax:click': function () {
        $('.scroller').removeClass('fadeIn').addClass('fadeOut');
        NProgress.start();
    },
    'pjax:start': function () {
        $('.scroller').css('opacity','0');
    },
    'pjax:end': function () {
        NProgress.done();
        $('.scroller').css('opacity','1').removeClass('fadeOut').addClass('fadeIn');
        afterPjax();
        $('#navbar-toc').hide();
        $('.nexus').css('width', 'auto');
        $('#navbar-title a').hide();
    },
    'pjax:popstate': function () {
        setTimeout("$('#toc').find('li').remove();",100);
        setTimeout("generateTOC()",200);
        setTimeout("$('#comment-box').children().remove();",100);
    },
});

<|endoftext|>


<commit_before>import Types from '../actions/actionTypes';

const initialState = {
  createSuccess: false,
  getGrpSuccess: false,
  getGrpUsersSuccess: false,
  editSuccess: false,
  archiveSuccess: false,
  newGroup: {},
  groups: []
};

const groupReducer = (state = initialState, action = {}) => {
  switch (action.type) {
    case Types.GET_USER_GROUPS:
      return Object.assign({}, state, {
        groups: action.allGroups.found,
        getGrpSuccess: !!Object.keys(action.allGroups)
      });

    case Types.GET_GROUP_USERS:
      return action.grpUsers;

    case Types.CREATE_GROUP:
      return Object.assign({}, state, {
        newGroup: action.newGroup,
        createSuccess: !!Object.keys(action.newGroup)
      });

    case Types.EDIT_A_GROUP:
      return action.updatedGroup;

    case Types.ARCHIVE_A_GROUP:
      return action.archivedGroup;

    case Types.GET_USER_GROUPS_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        getGrpSuccess: false
      });

    case Types.GET_GROUP_USERS_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        getGrpUsersSuccess: false
      });

    case Types.CREATE_GROUP_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        createSuccess: false
      });

    case Types.EDIT_A_GROUP_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        editSuccess: false
      });

    case Types.ARCHIVE_A_GROUP_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        archiveSuccess: false
      });

    default: return state;
  }
};

export default groupReducer;
<commit_msg>refactored group Reducer<commit_after>import Types from '../actions/actionTypes';

const initialState = {
  createSuccess: false,
  getGrpSuccess: false,
  getGrpUsersSuccess: false,
  editSuccess: false,
  archiveSuccess: false,
  newGroup: {},
  groups: {}
};

const groupReducer = (state = initialState, action = {}) => {
  switch (action.type) {
    case Types.GET_USER_GROUPS:
      return Object.assign({}, state, {
        groups: action.allGroups.found,
        getGrpSuccess: !!Object.keys(action.allGroups)
      });

    case Types.GET_GROUP_USERS:
      return action.grpUsers;

    case Types.CREATE_GROUP:
      return Object.assign({}, state, {
        newGroup: action.newGroup,
        createSuccess: !!Object.keys(action.newGroup)
      });

    case Types.EDIT_A_GROUP:
      return action.updatedGroup;

    case Types.ARCHIVE_A_GROUP:
      return action.archivedGroup;

    case Types.GET_USER_GROUPS_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        getGrpSuccess: false
      });

    case Types.GET_GROUP_USERS_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        getGrpUsersSuccess: false
      });

    case Types.CREATE_GROUP_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        createSuccess: false
      });

    case Types.EDIT_A_GROUP_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        editSuccess: false
      });

    case Types.ARCHIVE_A_GROUP_FAILURE:
      return Object.assign({}, state, {
        errors: action.failure,
        archiveSuccess: false
      });

    default: return state;
  }
};

export default groupReducer;
<|endoftext|>


<commit_before>mapkob = Object.create(null);

/**
 * Generic function to prepare input for consumption
 *
 * Type can be one of:
 *  - "newline delim": Take a string where sentences are delimited by newlines
 *  -
 *
 * @param {Object} data The input data
 * @param {String} type The type of input
 * @returns {Array} An array of strings, sentences delimited by undefined
 */
mapkob.prepareInput = function(data, type) {
  function splitSentenceArray(a) {
    var delimited = [];
    a.map(function(sentence, i) {
      delimited.push(sentence);
      if (i < sentences.length - 1) {
        delimited.push(undefined)
      }
    });
    return delimited
  }

  function flattenSentenceArray(a) {
    var wordSplitRe = new RegExp("[ \.]+")
    return a.map(function(sentence) {
      return sentence === undefined ? [undefined] : sentence.split(wordSplitRe);
    }).reduce(function(x,y) {return x.concat(y)})
  }

  // newline delim
  var splitRe = new RegExp("[\n\r\.\!\?\t]+")
  if (type === "newline delim") {
    var sentences = data.split(splitRe);
    var delimited = splitSentenceArray(sentences);
    return flattenSentenceArray(delimited);

  }

  // sentence array
  if (type === "sentence array") {
    var delimited = splitSentenceArray(sentences);
    return flattenSentenceArray(delimited);
  }
  return
}

/**
 * Creates and empty Transition matrix
 *
 * @returns {Object} A Transition Matrix object
 */
mapkob.TransitionMatrix = function(words) {
  var uniqueWords = [];
  var matrix = {};
  var starts = {};

  this.stateSpace = [];
  this.matrix = {};
  this.initialStates = new mapkob.Row();
  return this;
}

/**
 * functional wrapper around constructor
 */
mapkob.transitionMatrix = function(words) {
  return new mapkob.TransitionMatrix(words);
}

/**
 * Adds training data to an existing model
 *
 * @param {Array} words An array of consecutive words. delimited by undefined
 * @returns {this} The trained model
 */
mapkob.TransitionMatrix.prototype.update = function(words) {
  // State space
  words.map(function(word, i) {
    if (this.stateSpace.indexOf(word) === -1) {
      this.stateSpace.push(word);
    }

    // Initial states
    if (this.initialStates.row[word] === undefined) {
      this.initialStates.row[word] = 1;
      this.initialStates.stateSpace.push(word);
    } else {
      this.initialStates.row[word] += 1;
    }

    // Rows
    if (this.matrix[word] === undefined) {
      this.matrix[word] = {};
    }
    var nextWord = words[i + 1];
    // Columns
    if (this.matrix[word][nextWord] === undefined) {
      this.matrix[word][nextWord] = 1;
    } else {
      this.matrix[word][nextWord] += 1;
    }
  }, this)
  return this;
}

/**
 * Returns the row of a matrix
 *
 * @param {String} row The row by name to look up
 * @returns {Object} The row of the matrix
 */
mapkob.TransitionMatrix.prototype.getRow = function(row) {
  var row = new mapkob.Row(this.matrix[row]);
  return row;
}

/**
 * Generates a Markov chain
 *
 * @returns {String} A Computer generated string
 */
mapkob.TransitionMatrix.prototype.generateChain = function() {
  var currentState = this.initialStates
                         .probabilities()
                         .cumSum()
                         .pickState(Math.random())
  var output = [];

  while (currentState !== "undefined" && currentState !== undefined) {
    output.push(currentState);
    var cumSums = this.getRow(currentState).probabilities().cumSum()
    currentState = cumSums.pickState(Math.random());
  }
  return output.join(" ");
}

/**
 * A Row mapkob row constructor
 *
 * @param {Object} input A simple object
 * @returns {Object} A maokob row
 */
mapkob.Row = function(input) {
  if (input === undefined) {
    this.row = {};
    this.stateSpace = [];
  } else {
    this.row = input;
    this.stateSpace = Object.keys(input);
  }
  return this;
}

/**
 * Calculates the sum of the rows
 *
 * @returns {Number} The sum of the values
 */
mapkob.Row.prototype.sum = function() {
  return this.stateSpace.map(function(state) {
    return this.row[state];
  }, this).reduce(function(x, y) {
    return x + y;
  })
}

/**
 * Calculates relative frequencies of a row
 *
 * @returns {Object} A row
 */
mapkob.Row.prototype.probabilities = function() {
  var sum = this.sum();
  var probs = {};
  this.stateSpace.map(function(state) {probs[state] = this.row[state] / sum}, this);
  return new mapkob.Row(probs)
}

/**
 * A row with the cumulative sums
 *
 * @returns {Object} A row
 */
mapkob.Row.prototype.cumSum = function() {
  var sums = {};
  var sum = 0;
  this.stateSpace.map(function(state) {
    sum += this.row[state];
    sums[state] = sum;
  }, this);
  return new mapkob.Row(sums);
}

/**
 * Returns an array with the row's values
 *
 * @returns {Array} The rows values
 */
mapkob.Row.prototype.values = function() {
  return this.stateSpace.map(function(state) {
    return this.row[state]
  }, this);
}

/**
 * Picks the state with the largest CDF that is smaller or equal to p
 * Technically the first one where the next is larger or the array ends
 *
 * @returns {String} A state string
 */
mapkob.Row.prototype.pickState = function(p) {
  cdf = this.values();
  for (var col in cdf) {
    if (p <= cdf[col] && (cdf[col + 1] == undefined || cdf[col + 1] > p)) {
      return this.stateSpace[col];
    }
  }
}
<commit_msg>funct. contr. can initialize & Method name change<commit_after>mapkob = Object.create(null);

/**
 * Generic function to prepare input for consumption
 *
 * Type can be one of:
 *  - "newline delim": Take a string where sentences are delimited by newlines
 *  -
 *
 * @param {Object} data The input data
 * @param {String} type The type of input
 * @returns {Array} An array of strings, sentences delimited by undefined
 */
mapkob.prepareInput = function(data, type) {
  function splitSentenceArray(a) {
    var delimited = [];
    a.map(function(sentence, i) {
      delimited.push(sentence);
      if (i < sentences.length - 1) {
        delimited.push(undefined)
      }
    });
    return delimited
  }

  function flattenSentenceArray(a) {
    var wordSplitRe = new RegExp("[ \.]+")
    return a.map(function(sentence) {
      return sentence === undefined ? [undefined] : sentence.split(wordSplitRe);
    }).reduce(function(x,y) {return x.concat(y)})
  }

  // newline delim
  var splitRe = new RegExp("[\n\r\.\!\?\t]+")
  if (type === "newline delim") {
    var sentences = data.split(splitRe);
    var delimited = splitSentenceArray(sentences);
    return flattenSentenceArray(delimited);

  }

  // sentence array
  if (type === "sentence array") {
    var delimited = splitSentenceArray(sentences);
    return flattenSentenceArray(delimited);
  }
  return
}

/**
 * Creates and empty Transition matrix
 *
 * @returns {Object} A Transition Matrix object
 */
mapkob.TransitionMatrix = function() {
  var uniqueWords = [];
  var matrix = {};
  var starts = {};

  this.stateSpace = [];
  this.matrix = {};
  this.initialStates = new mapkob.Row();
  return this;
}

/**
 * functional wrapper around constructor
 */
mapkob.transitionMatrix = function(words) {
  var output =  new mapkob.TransitionMatrix();
  if (words !== undefined) {output.train(words);}
  return output;
}

/**
 * Adds training data to an existing model
 *
 * @param {Array} words An array of consecutive words. delimited by undefined
 * @returns {this} The trained model
 */
mapkob.TransitionMatrix.prototype.train = function(words) {
  // State space
  words.map(function(word, i) {
    if (this.stateSpace.indexOf(word) === -1) {
      this.stateSpace.push(word);
    }

    // Initial states
    if (this.initialStates.row[word] === undefined) {
      this.initialStates.row[word] = 1;
      this.initialStates.stateSpace.push(word);
    } else {
      this.initialStates.row[word] += 1;
    }

    // Rows
    if (this.matrix[word] === undefined) {
      this.matrix[word] = {};
    }
    var nextWord = words[i + 1];
    // Columns
    if (this.matrix[word][nextWord] === undefined) {
      this.matrix[word][nextWord] = 1;
    } else {
      this.matrix[word][nextWord] += 1;
    }
  }, this)
  return this;
}

/**
 * Returns the row of a matrix
 *
 * @param {String} row The row by name to look up
 * @returns {Object} The row of the matrix
 */
mapkob.TransitionMatrix.prototype.getRow = function(row) {
  var row = new mapkob.Row(this.matrix[row]);
  return row;
}

/**
 * Generates a Markov chain
 *
 * @returns {String} A Computer generated string
 */
mapkob.TransitionMatrix.prototype.generateChain = function() {
  var currentState = this.initialStates
                         .probabilities()
                         .cumSum()
                         .pickState(Math.random())
  var output = [];

  while (currentState !== "undefined" && currentState !== undefined) {
    output.push(currentState);
    var cumSums = this.getRow(currentState).probabilities().cumSum()
    currentState = cumSums.pickState(Math.random());
  }
  return output.join(" ");
}

/**
 * A Row mapkob row constructor
 *
 * @param {Object} input A simple object
 * @returns {Object} A maokob row
 */
mapkob.Row = function(input) {
  if (input === undefined) {
    this.row = {};
    this.stateSpace = [];
  } else {
    this.row = input;
    this.stateSpace = Object.keys(input);
  }
  return this;
}

/**
 * Calculates the sum of the rows
 *
 * @returns {Number} The sum of the values
 */
mapkob.Row.prototype.sum = function() {
  return this.stateSpace.map(function(state) {
    return this.row[state];
  }, this).reduce(function(x, y) {
    return x + y;
  })
}

/**
 * Calculates relative frequencies of a row
 *
 * @returns {Object} A row
 */
mapkob.Row.prototype.probabilities = function() {
  var sum = this.sum();
  var probs = {};
  this.stateSpace.map(function(state) {probs[state] = this.row[state] / sum}, this);
  return new mapkob.Row(probs)
}

/**
 * A row with the cumulative sums
 *
 * @returns {Object} A row
 */
mapkob.Row.prototype.cumSum = function() {
  var sums = {};
  var sum = 0;
  this.stateSpace.map(function(state) {
    sum += this.row[state];
    sums[state] = sum;
  }, this);
  return new mapkob.Row(sums);
}

/**
 * Returns an array with the row's values
 *
 * @returns {Array} The rows values
 */
mapkob.Row.prototype.values = function() {
  return this.stateSpace.map(function(state) {
    return this.row[state]
  }, this);
}

/**
 * Picks the state with the largest CDF that is smaller or equal to p
 * Technically the first one where the next is larger or the array ends
 *
 * @returns {String} A state string
 */
mapkob.Row.prototype.pickState = function(p) {
  cdf = this.values();
  for (var col in cdf) {
    if (p <= cdf[col] && (cdf[col + 1] == undefined || cdf[col + 1] > p)) {
      return this.stateSpace[col];
    }
  }
}
<|endoftext|>


<commit_before>"use strict";

import Network  from   "../constants/network";
import wrapper     from   "../constants/wrapper";

const requests = [
  "REVIEW_ASSESSMENT_LOADED",
  "REVIEW_RESULT_LOADED"
];

const actions  = [
  "REVIEW_ASSESSMENT_LOAD_PENDING",
  "REVIEW_RESULT_LOAD_PENDING"
];

export const Constants = wrapper(requests, actions);

export const loadAssessment = (settings) => ({
  type: Constants.REVIEW_ASSESSMENT_LOAD_PENDING,
  method: Network.GET,
  url: (url.indexOf("?") > -1) ? `${settings.srcUrl}&for_review=` : `${settings.srcUrl}?for_review=1`
});

export const loadAssessmentResult = (assessmentId, resultId) => ({
  type: Constants.REVIEW_RESULT_LOAD_PENDING,
  method: Network.GET,
  url: `/api/assessments/${assessmentId}/results/${resultId}`
}
<commit_msg>Fix syntax error<commit_after>"use strict";

import Network  from   "../constants/network";
import wrapper     from   "../constants/wrapper";

const requests = [
  "REVIEW_ASSESSMENT_LOADED",
  "REVIEW_RESULT_LOADED"
];

const actions  = [
  "REVIEW_ASSESSMENT_LOAD_PENDING",
  "REVIEW_RESULT_LOAD_PENDING"
];

export const Constants = wrapper(requests, actions);

export const loadAssessment = (settings) => ({
  type: Constants.REVIEW_ASSESSMENT_LOAD_PENDING,
  method: Network.GET,
  url: (url.indexOf("?") > -1) ? `${settings.srcUrl}&for_review=` : `${settings.srcUrl}?for_review=1`
});

export const loadAssessmentResult = (assessmentId, resultId) => ({
  type: Constants.REVIEW_RESULT_LOAD_PENDING,
  method: Network.GET,
  url: `/api/assessments/${assessmentId}/results/${resultId}`
});
<|endoftext|>


<commit_before>var clickedToggle = new String();
var toggleMap = new Object();

Template.toggle.rendered = function () {
  for (var item in toggleMap) {
    node = $('.' + item).children();
    toggle(node,toggleMap[item]);
    console.log(item);
  };
};

Template.toggle.helpers({
  value: function () {
    if (this.setting == clickedToggle) {
      var node = $('.' + this.setting).children();
      toggle(node,this.value);
    } else {
      if (toggleMap[this.setting] == undefined) {
        toggleMap[this.setting] = this.value;
      }
    };
  },
  setting: function () {
    return this.setting;
  }
});

Template.toggle.events({
  "click #toggleButton": function () {
    clickedToggle = this.setting;
    var obj = new Object;
    obj[this.setting] = !this.value;
    Contracts.update({_id: Session.get('contractId')}, { $set: obj });
  }
});

function toggle (node, value) {

  if (value) {

    node
      .velocity("stop")
      .velocity({'margin-left': '2px'}, Modules.client.animationSettings)
      .velocity({'margin-left': '42px'}, Modules.client.animationSettings)
      .velocity("stop");

    node.parent().first()
      .velocity("stop")
      .velocity({'backgroundColor': '#ccc'}, Modules.client.animationSettings)
      .velocity({'backgroundColor': '#00bf8f'}, Modules.client.animationSettings)
      .velocity("stop");

  } else {

    node
      .velocity("stop")
      .velocity({'margin-left': '42px'}, Modules.client.animationSettings)
      .velocity({'margin-left': '2px'}, Modules.client.animationSettings)
      .velocity("stop");

    node.parent().first()
      .velocity("stop")
      .velocity({'backgroundColor': '#00bf8f'}, Modules.client.animationSettings)
      .velocity({'backgroundColor': '#ccc'}, Modules.client.animationSettings)
      .velocity("stop");

  }
}
<commit_msg>fake it till you make it toggles<commit_after>var clickedToggle = new String();
var toggleMap = new Object();

Template.toggle.rendered = function () {
  for (var item in toggleMap) {
    node = $('.' + item).children();
    toggle(node,toggleMap[item]);
  };
};

Template.toggle.helpers({
  value: function () {
    if (this.setting == clickedToggle) {
      var node = $('.' + this.setting).children();
      //toggle(node,this.value);
    } else {
      if (toggleMap[this.setting] == undefined) {
        toggleMap[this.setting] = this.value;
      }
    };
  },
  setting: function () {
    return this.setting;
  }
});

Template.toggle.events({
  "click #toggleButton": function (event) {
    clickedToggle = this.setting;
    var obj = new Object;

    //console.log(event.target);
    toggle($('.' + this.setting).children(), !this.value);

    //Contracts.update({_id: Session.get('contractId')}, { this.setting: !this.value });
    Meteor.call("updateContractField", Session.get('contractId'), this.setting, !this.value);
  }
});

function toggle (node, value) {
  console.log(node + ' ' + value);

  if (value) {

    node
      .velocity("stop")
      .velocity({'margin-left': '2px'}, Modules.client.animationSettings)
      .velocity({'margin-left': '42px'}, Modules.client.animationSettings)
      .velocity("stop");

    node.parent().first()
      .velocity("stop")
      .velocity({'backgroundColor': '#ccc'}, Modules.client.animationSettings)
      .velocity({'backgroundColor': '#00bf8f'}, Modules.client.animationSettings)
      .velocity("stop");

  } else {

    node
      .velocity("stop")
      .velocity({'margin-left': '42px'}, Modules.client.animationSettings)
      .velocity({'margin-left': '2px'}, Modules.client.animationSettings)
      .velocity("stop");

    node.parent().first()
      .velocity("stop")
      .velocity({'backgroundColor': '#00bf8f'}, Modules.client.animationSettings)
      .velocity({'backgroundColor': '#ccc'}, Modules.client.animationSettings)
      .velocity("stop");

  }
}
<|endoftext|>


<commit_before>/* global google */

var React = require('react')

module.exports = React.createClass({
  componentDidMount: function () { this.updateMarker(this.props) },
  componentWillReceiveProps: function (newProps) { this.updateMarker(newProps) },

  getInitialState: function () {
    return {}
  },

  componentWillUnmount: function () {
    var marker = this.state.marker
    if (!marker) return

    marker.setMap(null)
  },

  updateMarker: function (newProps) {
    var marker = this.state.marker

    // create new marker
    if (!marker) {
      marker = new google.maps.Marker(newProps)

    // update existing marker
    } else {
      marker.setOptions(newProps)
    }

    this.setState({ marker: marker })
  },

  render: function () {
    return null
  }
})

module.exports.Animation = google.maps.Animation
<commit_msg>marker: don't bother with state<commit_after>/* global google */

var React = require('react')

module.exports = React.createClass({
  componentWillUnmount: function () {
    if (!this.marker) return

    this.marker.setMap(null)
  },

  render: function () {
    // create new marker
    if (!this.marker) {
      this.marker = new google.maps.Marker(this.props)

    // update existing marker
    } else {
      this.marker.setOptions(this.props)
    }

    return null
  }
})

module.exports.Animation = google.maps.Animation
<|endoftext|>


<commit_before>/*jslint plusplus: true */
/*global hilary*/

hilary.register('gutentyp::toolbar', { init: function (config, utils, componentCollection) {
    "use strict";

    var build = function () {
        var components = componentCollection.components,
            i,
            formatEventSelector,
            buttonTemplate,
            groups = {},
            addWithDisplayHandler,
            addWithGroup,
            addGroup,
            add;

        formatEventSelector = function (component) {
            return config.selectors.toolbar + ' .' + component.cssClass + ':not(' + config.selectors.hasEvents + ')';
        };

        buttonTemplate = function (component, componentId) {
            var buttonClass, template;

            buttonClass = 'gutentyp-component ' + component.cssClass;

            if(componentId) {
                buttonClass += ' ' + componentId;
            }

            template = '<button type="button" class="' + buttonClass + '">'
                                + ''
                                + '' + component.title + ''
                            + '</button>';
            return template;
        };

        add = function (component) {
            utils.insertNewElementInto({
                markup: buttonTemplate(component)
            }, config.selectors.newToolbars);
            utils.attachEvent(formatEventSelector(component), 'click', component.execute);
        };

        addWithDisplayHandler = function (component) {
            utils.insertHtml(config.selectors.newToolbars, component.displayHandler());
            utils.attachEvent(formatEventSelector(component), 'click', component.execute);
        };

        addGroup = function (component) {
            var currentGroup = groups[component.group.name] = { components: [component] };
            currentGroup.toggleId = utils.getRandomString();// component.group.name + 'toggle';
            currentGroup.menuId = utils.getRandomString(); // component.group.name + 'menu';//utils.getRandomString();
            currentGroup.toggleSelector = '.' + currentGroup.toggleId;
            currentGroup.menuSelector = '.' + currentGroup.menuId;

            utils.insertNewElementInto({
                markup: buttonTemplate(component.group, currentGroup.toggleId)
            }, config.selectors.newToolbars);
            utils.insertNewElementInto({
                markup: '

'
            }, config.selectors.newToolbars);

            // toggle hidden
            utils.attachEvent(currentGroup.toggleSelector, 'click', function (event) {
                var btnCoords = utils.getCoordinates(event.target),
                    style;

                // set the coordinates
                style = 'left: ' + ((btnCoords.left + (btnCoords.width / 2)) / 2);
                style += '; top: ' + (btnCoords.offset.top + btnCoords.height + 6);
                utils.setStyle(currentGroup.menuSelector, style);

                // hide any other toolbars that might be open
                utils.toggleClass('.gutentyp-toolbar-group.active:not(' + currentGroup.menuSelector + ')', 'active');
                // show or hid this toolbar
                utils.toggleClass(currentGroup.menuSelector, 'active');
            });

            return currentGroup;
        };

        addWithGroup = function (component) {
            var componentId = utils.getRandomString(),
                componentSelector = '.' + componentId,
                currentGroup,
                execWrapper;

            if (!groups[component.group.name]) {
                currentGroup = addGroup(component);
            } else {
                currentGroup = groups[component.group.name];
                groups[component.group.name].components.push(component);
            }

            if (component.displayHandler) {
                utils.insertNewElementInto({
                    markup: '
' + component.displayHandler(componentId) + '
'
                }, currentGroup.menuSelector + ' ul');
            } else {
                utils.insertNewElementInto({
                    markup: '
' + buttonTemplate(component, componentId) + '
'
                }, currentGroup.menuSelector + ' ul');
            }

            execWrapper = function (event, input) {
                component.execute(event, input);
                utils.toggleClass(currentGroup.menuSelector, 'active');
            };

            utils.attachEvent(componentSelector, 'click', execWrapper);
        };

        utils.insertNewElementBefore('div', config.selectors.newEditors, config.selectors.toolbar);

        for (i = 0; i < components.length; i++) {
            if (components[i].group !== undefined) {
                addWithGroup(components[i]);
            } else if (utils.isFunction(components[i].displayHandler)) {
                addWithDisplayHandler(components[i]);
            } else {
                add(components[i]);
            }
        }

        utils.addClass(config.selectors.newEditors, config.cssClasses.hasToolbar);
        utils.addClass(config.selectors.newToolbars, config.cssClasses.hasComponents);

        return;
    };

    return {
        build: build
    };

}});
<commit_msg>Fixes issue where popup toolbars were incorrectly centered<commit_after>/*jslint plusplus: true */
/*global hilary*/

hilary.register('gutentyp::toolbar', { init: function (config, utils, componentCollection) {
    "use strict";

    var build = function () {
        var components = componentCollection.components,
            i,
            formatEventSelector,
            buttonTemplate,
            groups = {},
            addWithDisplayHandler,
            addWithGroup,
            addGroup,
            add;

        formatEventSelector = function (component) {
            return config.selectors.toolbar + ' .' + component.cssClass + ':not(' + config.selectors.hasEvents + ')';
        };

        buttonTemplate = function (component, componentId) {
            var buttonClass, template;

            buttonClass = 'gutentyp-component ' + component.cssClass;

            if(componentId) {
                buttonClass += ' ' + componentId;
            }

            template = '<button type="button" class="' + buttonClass + '">'
                                + ''
                                + '' + component.title + ''
                            + '</button>';
            return template;
        };

        add = function (component) {
            utils.insertNewElementInto({
                markup: buttonTemplate(component)
            }, config.selectors.newToolbars);
            utils.attachEvent(formatEventSelector(component), 'click', component.execute);
        };

        addWithDisplayHandler = function (component) {
            utils.insertHtml(config.selectors.newToolbars, component.displayHandler());
            utils.attachEvent(formatEventSelector(component), 'click', component.execute);
        };

        addGroup = function (component) {
            var currentGroup = groups[component.group.name] = { components: [component] };
            currentGroup.toggleId = utils.getRandomString();// component.group.name + 'toggle';
            currentGroup.menuId = utils.getRandomString(); // component.group.name + 'menu';//utils.getRandomString();
            currentGroup.toggleSelector = '.' + currentGroup.toggleId;
            currentGroup.menuSelector = '.' + currentGroup.menuId;

            utils.insertNewElementInto({
                markup: buttonTemplate(component.group, currentGroup.toggleId)
            }, config.selectors.newToolbars);
            utils.insertNewElementInto({
                markup: '

'
            }, config.selectors.newToolbars);

            // toggle hidden
            utils.attachEvent(currentGroup.toggleSelector, 'click', function (event) {
                var btnCoords = utils.getCoordinates(event.target),
                    style;

                // set the coordinates
                style = 'left: ' + (btnCoords.left + (btnCoords.width / 2) - (utils.getCoordinates(currentGroup.menuSelector).width / 2));
                style += '; top: ' + (btnCoords.offset.top + btnCoords.height + 6);
                utils.setStyle(currentGroup.menuSelector, style);

                // hide any other toolbars that might be open
                utils.toggleClass('.gutentyp-toolbar-group.active:not(' + currentGroup.menuSelector + ')', 'active');
                // show or hid this toolbar
                utils.toggleClass(currentGroup.menuSelector, 'active');
            });

            return currentGroup;
        };

        addWithGroup = function (component) {
            var componentId = utils.getRandomString(),
                componentSelector = '.' + componentId,
                currentGroup,
                execWrapper;

            if (!groups[component.group.name]) {
                currentGroup = addGroup(component);
            } else {
                currentGroup = groups[component.group.name];
                groups[component.group.name].components.push(component);
            }

            if (component.displayHandler) {
                utils.insertNewElementInto({
                    markup: '
' + component.displayHandler(componentId) + '
'
                }, currentGroup.menuSelector + ' ul');
            } else {
                utils.insertNewElementInto({
                    markup: '
' + buttonTemplate(component, componentId) + '
'
                }, currentGroup.menuSelector + ' ul');
            }

            execWrapper = function (event, input) {
                component.execute(event, input);
                utils.toggleClass(currentGroup.menuSelector, 'active');
            };

            utils.attachEvent(componentSelector, 'click', execWrapper);
        };

        utils.insertNewElementBefore('div', config.selectors.newEditors, config.selectors.toolbar);

        for (i = 0; i < components.length; i++) {
            if (components[i].group !== undefined) {
                addWithGroup(components[i]);
            } else if (utils.isFunction(components[i].displayHandler)) {
                addWithDisplayHandler(components[i]);
            } else {
                add(components[i]);
            }
        }

        utils.addClass(config.selectors.newEditors, config.cssClasses.hasToolbar);
        utils.addClass(config.selectors.newToolbars, config.cssClasses.hasComponents);

        return;
    };

    return {
        build: build
    };

}});
<|endoftext|>


<commit_before>import {getGlobal} from '../src/prebidGlobal.js';
import {ajax} from '../src/ajax.js';
import {config} from '../src/config.js';
import * as utils from '../src/utils.js';
import MD5 from 'crypto-js/md5.js';

let email;
let conf;
const LOG_PRE_FIX = 'ID-Library: ';
const CONF_DEFAULT_OBSERVER_DEBOUNCE_MS = 250;
const CONF_DEFAULT_FULL_BODY_SCAN = false;
const OBSERVER_CONFIG = {
  subtree: true,
  attributes: true,
  attributeOldValue: false,
  childList: true,
  attirbuteFilter: ['value'],
  characterData: true,
  characterDataOldValue: false
};
const logInfo = createLogInfo(LOG_PRE_FIX);
const logError = createLogError(LOG_PRE_FIX);

function createLogInfo(prefix) {
  return function (...strings) {
    utils.logInfo(prefix + ' ', ...strings);
  }
}

function createLogError(prefix) {
  return function (...strings) {
    utils.logError(prefix + ' ', ...strings);
  }
}

function getEmail(value) {
  const matched = value.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
  if (!matched) {
    return null;
  }
  logInfo('Email found: ' + matched[0]);
  return matched[0];
}

function bodyAction(mutations, observer) {
  logInfo('BODY observer on debounce called');
  // If the email is found in the input element, disconnect the observer
  if (email) {
    observer.disconnect();
    logInfo('Email is found, body observer disconnected');
    return;
  }

  const body = document.body.innerHTML;
  email = getEmail(body);
  if (email !== null) {
    logInfo(`Email obtained from the body ${email}`);
    observer.disconnect();
    logInfo('Post data on email found in body');
    postData();
  }
}

function targetAction(mutations, observer) {
  logInfo('Target observer called');
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      email = node.textContent;

      if (email) {
        logInfo('Email obtained from the target ' + email);
        observer.disconnect();
        logInfo('Post data on email found in target');
        postData();
        return;
      }
    }
  }
}

function addInputElementsElementListner(conf) {
  logInfo('Adding input element listeners');
  const inputs = document.querySelectorAll('input[type=text], input[type=email]');

  for (var i = 0; i < inputs.length; i++) {
    logInfo(`Original Value in Input = ${inputs[i].value}`);
    inputs[i].addEventListener('change', event => processInputChange(event));
    inputs[i].addEventListener('blur', event => processInputChange(event));
  }
}

function removeInputElementsElementListner() {
  logInfo('Removing input element listeners');
  const inputs = document.querySelectorAll('input[type=text], input[type=email]');

  for (var i = 0; i < inputs.length; i++) {
    inputs[i].removeEventListener('change', event => processInputChange(event));
    inputs[i].removeEventListener('blur', event => processInputChange(event));
  }
}

function processInputChange(event) {
  const value = event.target.value;
  logInfo(`Modified Value of input ${event.target.value}`);
  email = getEmail(value);
  if (email !== null) {
    logInfo('Email found in input ' + email);
    postData();
    removeInputElementsElementListner();
  }
}

function debounce(func, wait, immediate) {
  var timeout;
  return function () {
    const context = this;
    const args = arguments;
    const later = function () {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    if (callNow) {
      func.apply(context, args);
    } else {
      logInfo('Debounce wait time ' + wait);
      timeout = setTimeout(later, wait);
    }
  };
};

function handleTargetElement() {
  const targetObserver = new MutationObserver(debounce(targetAction, conf.debounce, false));

  const targetElement = document.getElementById(conf.target);
  if (targetElement) {
    email = targetElement.innerText;

    if (!email) {
      logInfo('Finding the email with observer');
      targetObserver.observe(targetElement, OBSERVER_CONFIG);
    } else {
      logInfo('Target found with target ' + email);
      logInfo('Post data on email found in target with target');
      postData();
    }
  }
}

function handleBodyElements() {
  if (doesInputElementsHaveEmail()) {
    logInfo('Email found in input elements ' + email);
    logInfo('Post data on email found in target without');
    postData();
    return;
  }
  email = getEmail(document.body.innerHTML);
  if (email !== null) {
    logInfo('Email found in body ' + email);
    logInfo('Post data on email found in the body without observer');
    postData();
    return;
  }
  addInputElementsElementListner();
  if (conf.fullscan === true) {
    const bodyObserver = new MutationObserver(debounce(bodyAction, conf.debounce, false));
    bodyObserver.observe(document.body, OBSERVER_CONFIG);
  }
}

function doesInputElementsHaveEmail() {
  const inputs = document.getElementsByTagName('input');

  for (let index = 0; index < inputs.length; ++index) {
    const curInput = inputs[index];
    email = getEmail(curInput.value);
    if (email !== null) {
      return true;
    }
  }
  return false;
}

function syncCallback() {
  return {
    success: function () {
      logInfo('Data synced successfully.');
    },
    error: function () {
      logInfo('Data sync failed.');
    }
  }
}

function postData() {
  (getGlobal()).refreshUserIds();
  const userIds = (getGlobal()).getUserIds();
  if (Object.keys(userIds).length === 0) {
    logInfo('No user ids');
    return;
  }
  logInfo('Users' + JSON.stringify(userIds));
  const syncPayload = {};
  syncPayload.hid = MD5(email).toString();
  syncPayload.uids = JSON.stringify(userIds);
  const payloadString = JSON.stringify(syncPayload);
  logInfo(payloadString);
  ajax(conf.url, syncCallback(), payloadString, {method: 'POST', withCredentials: true});
}

function associateIds() {
  if (window.MutationObserver || window.WebKitMutationObserver) {
    if (conf.target) {
      handleTargetElement();
    } else {
      handleBodyElements();
    }
  }
}

export function setConfig(config) {
  if (!config) {
    logError('Required confirguration not provided');
    return;
  }
  if (!config.url) {
    logError('The required url is not configured');
    return;
  }
  if (typeof config.debounce !== 'number') {
    config.debounce = CONF_DEFAULT_OBSERVER_DEBOUNCE_MS;
    logInfo('Set default observer debounce to ' + CONF_DEFAULT_OBSERVER_DEBOUNCE_MS);
  }
  if (typeof config.fullscan !== 'boolean') {
    config.fullscan = CONF_DEFAULT_FULL_BODY_SCAN;
    logInfo('Set default fullscan ' + CONF_DEFAULT_FULL_BODY_SCAN);
  }
  conf = config;
  associateIds();
}

config.getConfig('idLibrary', config => setConfig(config.idLibrary));
<commit_msg>Updating send json userids to endpoint in idLibrary (#6219)<commit_after>import {getGlobal} from '../src/prebidGlobal.js';
import {ajax} from '../src/ajax.js';
import {config} from '../src/config.js';
import * as utils from '../src/utils.js';
import MD5 from 'crypto-js/md5.js';

let email;
let conf;
const LOG_PRE_FIX = 'ID-Library: ';
const CONF_DEFAULT_OBSERVER_DEBOUNCE_MS = 250;
const CONF_DEFAULT_FULL_BODY_SCAN = false;
const OBSERVER_CONFIG = {
  subtree: true,
  attributes: true,
  attributeOldValue: false,
  childList: true,
  attirbuteFilter: ['value'],
  characterData: true,
  characterDataOldValue: false
};
const logInfo = createLogInfo(LOG_PRE_FIX);
const logError = createLogError(LOG_PRE_FIX);

function createLogInfo(prefix) {
  return function (...strings) {
    utils.logInfo(prefix + ' ', ...strings);
  }
}

function createLogError(prefix) {
  return function (...strings) {
    utils.logError(prefix + ' ', ...strings);
  }
}

function getEmail(value) {
  const matched = value.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+)/gi);
  if (!matched) {
    return null;
  }
  logInfo('Email found: ' + matched[0]);
  return matched[0];
}

function bodyAction(mutations, observer) {
  logInfo('BODY observer on debounce called');
  // If the email is found in the input element, disconnect the observer
  if (email) {
    observer.disconnect();
    logInfo('Email is found, body observer disconnected');
    return;
  }

  const body = document.body.innerHTML;
  email = getEmail(body);
  if (email !== null) {
    logInfo(`Email obtained from the body ${email}`);
    observer.disconnect();
    logInfo('Post data on email found in body');
    postData();
  }
}

function targetAction(mutations, observer) {
  logInfo('Target observer called');
  for (const mutation of mutations) {
    for (const node of mutation.addedNodes) {
      email = node.textContent;

      if (email) {
        logInfo('Email obtained from the target ' + email);
        observer.disconnect();
        logInfo('Post data on email found in target');
        postData();
        return;
      }
    }
  }
}

function addInputElementsElementListner(conf) {
  logInfo('Adding input element listeners');
  const inputs = document.querySelectorAll('input[type=text], input[type=email]');

  for (var i = 0; i < inputs.length; i++) {
    logInfo(`Original Value in Input = ${inputs[i].value}`);
    inputs[i].addEventListener('change', event => processInputChange(event));
    inputs[i].addEventListener('blur', event => processInputChange(event));
  }
}

function removeInputElementsElementListner() {
  logInfo('Removing input element listeners');
  const inputs = document.querySelectorAll('input[type=text], input[type=email]');

  for (var i = 0; i < inputs.length; i++) {
    inputs[i].removeEventListener('change', event => processInputChange(event));
    inputs[i].removeEventListener('blur', event => processInputChange(event));
  }
}

function processInputChange(event) {
  const value = event.target.value;
  logInfo(`Modified Value of input ${event.target.value}`);
  email = getEmail(value);
  if (email !== null) {
    logInfo('Email found in input ' + email);
    postData();
    removeInputElementsElementListner();
  }
}

function debounce(func, wait, immediate) {
  var timeout;
  return function () {
    const context = this;
    const args = arguments;
    const later = function () {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    if (callNow) {
      func.apply(context, args);
    } else {
      logInfo('Debounce wait time ' + wait);
      timeout = setTimeout(later, wait);
    }
  };
};

function handleTargetElement() {
  const targetObserver = new MutationObserver(debounce(targetAction, conf.debounce, false));

  const targetElement = document.getElementById(conf.target);
  if (targetElement) {
    email = targetElement.innerText;

    if (!email) {
      logInfo('Finding the email with observer');
      targetObserver.observe(targetElement, OBSERVER_CONFIG);
    } else {
      logInfo('Target found with target ' + email);
      logInfo('Post data on email found in target with target');
      postData();
    }
  }
}

function handleBodyElements() {
  if (doesInputElementsHaveEmail()) {
    logInfo('Email found in input elements ' + email);
    logInfo('Post data on email found in target without');
    postData();
    return;
  }
  email = getEmail(document.body.innerHTML);
  if (email !== null) {
    logInfo('Email found in body ' + email);
    logInfo('Post data on email found in the body without observer');
    postData();
    return;
  }
  addInputElementsElementListner();
  if (conf.fullscan === true) {
    const bodyObserver = new MutationObserver(debounce(bodyAction, conf.debounce, false));
    bodyObserver.observe(document.body, OBSERVER_CONFIG);
  }
}

function doesInputElementsHaveEmail() {
  const inputs = document.getElementsByTagName('input');

  for (let index = 0; index < inputs.length; ++index) {
    const curInput = inputs[index];
    email = getEmail(curInput.value);
    if (email !== null) {
      return true;
    }
  }
  return false;
}

function syncCallback() {
  return {
    success: function () {
      logInfo('Data synced successfully.');
    },
    error: function () {
      logInfo('Data sync failed.');
    }
  }
}

function postData() {
  (getGlobal()).refreshUserIds();
  const userIds = (getGlobal()).getUserIds();
  if (Object.keys(userIds).length === 0) {
    logInfo('No user ids');
    return;
  }
  logInfo('Users' + userIds);
  const syncPayload = {};
  syncPayload.hid = MD5(email).toString();
  syncPayload.uids = userIds;
  const payloadString = JSON.stringify(syncPayload);
  logInfo(payloadString);
  ajax(conf.url, syncCallback(), payloadString, {method: 'POST', withCredentials: true});
}

function associateIds() {
  if (window.MutationObserver || window.WebKitMutationObserver) {
    if (conf.target) {
      handleTargetElement();
    } else {
      handleBodyElements();
    }
  }
}

export function setConfig(config) {
  if (!config) {
    logError('Required confirguration not provided');
    return;
  }
  if (!config.url) {
    logError('The required url is not configured');
    return;
  }
  if (typeof config.debounce !== 'number') {
    config.debounce = CONF_DEFAULT_OBSERVER_DEBOUNCE_MS;
    logInfo('Set default observer debounce to ' + CONF_DEFAULT_OBSERVER_DEBOUNCE_MS);
  }
  if (typeof config.fullscan !== 'boolean') {
    config.fullscan = CONF_DEFAULT_FULL_BODY_SCAN;
    logInfo('Set default fullscan ' + CONF_DEFAULT_FULL_BODY_SCAN);
  }
  conf = config;
  associateIds();
}

config.getConfig('idLibrary', config => setConfig(config.idLibrary));
<|endoftext|>