UNPKG

@snippetify/book-reader

Version:
184 lines (152 loc) 5.39 kB
const Events = require('./events') class MenuBuilder { constructor () { this.events = {} this.config = {} this.selection = null this.rootElement = document } static getInstance () { return new MenuBuilder() } setRootElement (element) { this.rootElement = element return this } setConfig (config) { this.config = config return this } setEvents (events) { this.events = events return this } initListeners () { this .onActionListener() .onSelectionListener() .hideContextMenuListener() .onNextOrPreviousClickedListener() } onSelectionListener () { this.events.subscribe(Events.textSelected, selection => { this.selection = selection this.print($(this.rootElement).find('.selection')) }) return this } hideContextMenuListener () { $(document).on('scroll', () => this.unprint()) $(this.rootElement).on('mousedown', e => { if ($(e.target).parents('[data-type="context-menu"]').length === 0) { this.unprint() } }) return this } onNextOrPreviousClickedListener () { $(this.rootElement).on('click', '[data-type="arrow-left"]', e => this.slideMenu(e.target, 'left')) $(this.rootElement).on('click', '[data-type="arrow-right"]', e => this.slideMenu(e.target, 'right')) return this } onActionListener () { $(this.rootElement).on('click', '[data-event]', e => { this.unprint() this.events.notify($(e.target).data('event'), this.selection) }) return this } build () { const content = $(this.config.template) content.find('[data-type="arrow-left"]').hide() content.find('[data-type="arrow-right"]').hide() this.config.items.forEach(item => { content .find('ul') .append( $('<li />') .html( $('<button />', { 'data-event': item.event }).text(item.name) ) ) }) return content } slideMenu (target, direction) { let slideWidth = 0 let leftDisabled = false let rightDisabled = false const slide = $(target).parents('.menu-wrapper').find('ul') const position = Math.abs(parseFloat(slide.css('left'))) const increment = $(target).parents('.menu-wrapper').find('.menu-inner').width() let leftGap = direction === 'right' ? (position + increment) : (position - increment) slide.find('li').each((_, v) => (slideWidth += $(v).width())) if ((leftGap + increment) > slideWidth) { rightDisabled = true leftGap = slideWidth - increment } if (leftGap < 0) { leftGap = 0 leftDisabled = true } $(target).parents('.menu-wrapper').find('[data-type="arrow-left"]').prop('disabled', leftDisabled) $(target).parents('.menu-wrapper').find('[data-type="arrow-right"]').prop('disabled', rightDisabled) slide.animate({ left: -leftGap }) } print (anchor) { const screenWidth = $(window).width() const anchorwidth = $(anchor).last().width() const anchorHeight = $(anchor).last().height() const anchorTop = $(anchor).last().offset().top const anchorCenter = $(anchor).last().offset().left + (anchorwidth / 2) let innerMenuWidth = 0 let menu = $(this.rootElement).find('[data-type="context-menu"]') // Create and Inject menu in DOM if not injected yet if (menu.length === 0) { $(this.rootElement).append(this.build()) menu = $(this.rootElement).find('[data-type="context-menu"]') } // Si le menu est plus large que l'ecran, activer le slider mode menu.find('li').each((_, elem) => { innerMenuWidth += $(elem).width() if ((innerMenuWidth + 120) > $(window).width()) { menu.find('[data-type="arrow-left"]').show() menu.find('[data-type="arrow-right"]').show() menu.find('.menu-inner').css({ maxWidth: innerMenuWidth }) return false } }) // Always reset slider menu.find('.menu-inner').find('ul').css({ left: 0 }) menu.find('[data-type="arrow-left"]').prop('disabled', true) const gap = 2 // decalage const menuWidth = menu.width() const menuHeight = menu.height() let menuLeft = anchorCenter - (menuWidth / 2) let menuTop = anchorTop + anchorHeight - 8 const menuTopToWindow = menuTop - $(window).scrollTop() // Selectionner le caret à afficher if ((menuTopToWindow + menuHeight + 30) > $(window).height()) { menuTop = anchorTop - menuHeight + 10 menu.find('[data-type="arrow-down"]').addClass('active') menu.find('[data-type="arrow-up"]').removeClass('active') } else { menu.find('[data-type="arrow-up"]').addClass('active') menu.find('[data-type="arrow-down"]').removeClass('active') } menuLeft = menuLeft < 0 ? gap : menuLeft menuLeft = (menuLeft + menuWidth) > screenWidth ? (screenWidth - menuWidth - gap) : menuLeft // Afficher le menu, positionner le caret ainsi que le menu menu.find('.arrow-wrapper').find('i').css({ marginLeft: anchorCenter - menuLeft - 7 }) menu.fadeIn().offset({ top: menuTop, left: menuLeft }) return this } unprint () { $(this.rootElement).find('[data-type="context-menu"]').fadeOut() } remove () { $(this.rootElement).find('[data-type="context-menu"]').remove() } } module.exports = MenuBuilder module.exports.default = MenuBuilder