diff --git a/lib/meta.js b/lib/meta.js index 47aa7961..76d1401c 100644 --- a/lib/meta.js +++ b/lib/meta.js @@ -14,113 +14,105 @@ } } if(typeof module !== "undefined"){ var common = module } - + /* UNBUILD */ ;USE(function(module){ - var noop = function(){}, u; $.fn.or = function(s){ return this.length ? this : $(s||'body') }; var m = window.meta = {edit:[]}; var k = m.key = {}; - k.meta = {17:17, 91:17, 93:17, 224:17}; // ctrl met - - function withMeta(eve){ return eve.metaKey || eve.ctrlKey } - + k.meta = {17:17, 91:17, 93:17, 224:17, 18: 17}; // ALT added + function withMeta(eve){ return eve.metaKey || eve.ctrlKey || eve.altKey } // ALT added + var defaults = { + 8: { // backspace: close root or go back on submenu + on: () => k.at == m.edit ? m.flip(false) : m.check('down', 'back') + }, + 27: { // esc: close and reset menu + up: () => k.wipe() + } + } k.down = function(eve){ - if(eve.repeat){ return } var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode; - - //if(!m.flip.is() && !k.meta[key]){ return } // cancel non-open events when closed TODO make optional - if(!k.meta[key] && withMeta(eve) && !k.at[key]) { return m.flip(false) } // cancel and close when no action and "meta key" held down (e.g. ctrl+c) - + if(eve.repeat){ return } + if(!k.meta[key] && withMeta(eve) && !k.at[key]) { + return m.flip(false) + } // cancel and close when no action and "meta key" held down (e.g. ctrl+c) if(!eve.fake && key === k.last){ return }; k.last = key; // jussi: polyfilling eve.repeat? if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length && !$(eve.target).closest('#meta').length){ - // if(k.meta[key]){ k.down.meta = key = -1 } - // if(!k.down.meta){ return } - - // prevent typing with meta open if(meta.flip.is() && !withMeta(eve)) eve.preventDefault() - - // hmmm? - // if(!k.meta[key] && !meta.flip.is()) return // aserwed } m.check('on', key, k.at || (k.at = m.edit)); - if(k.meta[key]){ - // m.list(k.at.back || m.edit); - // if(k.at){ m.flip() } // && !k.at.back - m.flip() - } + if(k.meta[key]){ m.flip() } } + k.down.keys = {} // currently pressed keys k.up = function(eve){ var tmp; var key = (k.eve = m.eve = eve).which = eve.which || eve.fake || eve.keyCode; - //if(!m.flip.is() && !k.meta[key]){ return } // ADDED cancel non-open events when closed TODO make optional - // if(!eve.fake && $(eve.target).closest('input, textarea, [contenteditable=true]').length){ - // if(k.meta[key]){ - // k.down.meta = null; - // key = -1; - // } else - // if(!k.down.meta){ return } - // } k.last = null; - // if($(':focus').closest('#meta').length){ return } m.check('up', key); - if(27 === eve.which){ k.wipe() } // -1 === key || + if(k.meta[key] && m.check.fired){ + m.close() + } } m.flip = function(tmp){ - var board = $('#meta .meta-menu'); - ((tmp === false) || (!tmp && board.is(':visible')))? - board.addClass('meta-none') - : board.removeClass('meta-none'); + ((tmp === false) || (!tmp && m.ui.board.is(':visible')))? + m.close() : m.open(); + } + m.open = function(){ + m.check.fired = null; + m.ui.board.removeClass('meta-none'); + } + m.close = function(){ + Object.keys(k.down.keys).forEach((keyDown) => { + m.check('up', keyDown); + }) + m.ui.board.addClass('meta-none') } m.flip.is = function(){ - return $('#meta .meta-menu').is(':visible'); + return m.ui.board.is(':visible'); } m.flip.wait = 500; m.check = function(how, key, at){ - at = k.at || m.edit; + if(!m.flip.is() && !k.meta[key]){ return } // TEMP: cancel non-open events when closed TODO make optional + at = k.at || m.edit; var next = at[key]; if(!next){ return } var tmp = k.eve || noop; if(tmp.preventDefault){ tmp.preventDefault()} // prevent typing (etc) when action found if(next[how]){ - //if(tmp.fake && !next.fake){ - //m.tap.next = next; - //} else { next[how](m.eve); - meta.ui.blink() - /*if(k.at !== m.next && 'up' === how){ - if(k.down.meta){ m.list(k.at = m.next) } - else { k.wipe() } - }*/ - //} + meta.ui.blink(); + m.check.fired = true; + if(how == 'up') delete k.down.keys[key] + else k.down.keys[key] = 1; } if('up' == how){ return } if(at != next){ next.back = at } (k.combo || (k.combo = [])).push(key); m.list(next, true); } + function defaultSort(a,b){ + a = a.combo.slice(-1)[0] || 0; + if(a.length){ a = a.toUpperCase().charCodeAt(0) } + b = b.combo.slice(-1)[0] || 0; + if(b.length){ b = b.toUpperCase().charCodeAt(0) } + return (a < b)? -1 : 1; + } m.list = function(at, opt){ if(!at){ return m.flip(false) } - // m.ui.depth(m.key.combo ? m.key.combo.length : 0) var l = []; - $.each(at, function(i,k){ 'back' != i && k.combo && k.name && l.push(k) }); + $.each(at, function(i,k){ 'back' != i && k && k.combo && k.name && l.push(k) }); if(!l.length){ return } k.at = at; - l = l.sort(function(a,b){ - a = a.combo.slice(-1)[0] || 0; - if(a.length){ a = a.toUpperCase().charCodeAt(0) } - b = b.combo.slice(-1)[0] || 0; - if(b.length){ b = b.toUpperCase().charCodeAt(0) } - return (a < b)? -1 : 1; - }); + if(at.sort !== null){ l = l.sort(at.sort || defaultSort) } var $ul = $('#meta .meta-menu ul') $ul.children('li').addClass('meta-none').hide(); setTimeout(function(){ $ul.children('.meta-none').remove() },250); // necessary fix for weird bug glitch $.each(l, function(i, k){ - $ul.append($('
  • ').text(k.name).data(k)); + var $li = $('
  • ').text(k.name).data(k) + $ul.append($li); + if(k.styles) meta.ui.iniline($li[0], k.styles); }); if(opt){ m.flip(true) } $ul.append($('
  • ').html('←').on('click', function(){ - // m.key.combo.pop() m.list(at.back); })); } @@ -139,7 +131,6 @@ $put.focus(); } k.wipe = function(opt){ - // k.down.meta = false; k.combo = []; if(!opt){ m.flip(false) } m.list(k.at = m.edit); @@ -150,19 +141,19 @@ .or($(document.elementFromPoint(meta.tap.x, meta.tap.y))); return on; } - meta.edit = function(edit){ - var tmp = edit.combow = []; - $.each(edit.combo || (edit.combo = []), function(i,k){ - if(!k || !k.length){ if('number' == typeof k){ tmp.push(k) } return } - tmp.push(k.toUpperCase().charCodeAt(0)); + meta.edit = function(e){ + var path = []; + $.each(e.combo || (e.combo = []), function(i,k){ + if(!k || !k.length){ if('number' == typeof k){ path.push(k) } return } + path.push(k.toUpperCase().charCodeAt(0)); }); - var at = meta.edit, l = edit.combo.length; - $.each(tmp, function(i,k){ at = at[k] = (++i >= l)? edit : at[k] || {} }); - edit.combow = edit.combow.join(','); + var at = meta.edit, l = e.combo.length; + $.each(path, function(i,k){ at = at[k] = at[k] || Object.create(defaults) }); + $.extend(at, e) // fixes overwriting when sub action is defined before parent + e.combow = path.join(','); // deprecate? m.list(k.at || meta.edit); } - - + $.extend(meta.edit, defaults) })(USE, './metaCore'); ;USE(function(module){ /* UI */ @@ -186,6 +177,7 @@ $m.append($('').html('☰').addClass('meta-start')); $m.append($('
    ').addClass('meta-menu meta-none').append('
      ')); $(document.body).append($m); + meta.ui.board = $('.meta-menu', $m); css({ '#meta': { display: 'block', @@ -195,7 +187,6 @@ background: 'white', 'font-size': '18pt', 'font-family': 'Tahoma, arial', - //'box-shadow': '0px 0px 1px #000044', 'border-radius': '1em', 'text-align': 'center', 'z-index': 999999, @@ -203,7 +194,6 @@ padding: 0, width: '2em', height: '2em', - opacity: 0.7, outline: 'none', color: '#000044', overflow: 'visible', @@ -231,31 +221,28 @@ }, '#meta .meta-menu ul li': { display: 'block', + 'float': 'right', background: 'white', + opacity: 0.7, padding: '0.5em 1em', 'border-radius': '1em', 'margin-left': '0.25em', 'margin-top': '0.25em', - 'float': 'right', 'cursor': 'pointer' }, + '#meta .meta-menu ul li:hover': { + opacity: 1 + }, '#meta a': {color: 'black'}, - // '#meta:hover': {opacity: 1}, '#meta .meta-menu ul:before': { content: "' '", display: 'block', 'min-height': '15em', height: '50vh' }, - // '#meta li': { - // background: 'white', - // padding: '0.5em 1em', - // 'border-radius': '1em', - // 'margin-left': '0.25em', - // 'margin-top': '0.25em', - // 'float': 'right' - // }, - // '#meta:hover .meta-menu': {display: 'block'} + '#meta .meta-start': { + cursor: 'pointer' + } }); function css(css){ var tmp = ''; @@ -270,201 +257,34 @@ tag.innerHTML = tmp; $m.append(tag) } - //}catch(e){} - - + meta.ui.iniline = function(el, cssObj){ + for(var k in cssObj) { el.style[k] = cssObj[k]; } + } })(USE, './metaUI'); - ;USE(function(module){ - - // include basic text editing by default. - var monotype = window.monotype || function(){console.log("monotype needed")}; - var m = meta; - m.text = {zws: '​'}; - m.text.on = function(eve){ var tmp; - if($((eve||{}).target).closest('#meta').length){ return } - m.text.range = null; - if(!(m.text.copy()||'').trim()){ - m.flip(false); - m.list(m.text.it); - return; - } - m.text.range = monotype((eve||{}).target); - m.text.it.on(eve); - } - m.text.copy = function(tmp){ - return ((tmp = window.getSelection) && tmp().toString()) || - ((tmp = document.selection) && tmp.createRange().text) || ''; - } - m.text.editor = function(opt, as){ var tmp; - if(!opt){ return } - opt = (typeof opt == 'string')? {edit: opt} : opt.tag? opt : {tag: opt}; - var r = opt.range = opt.range || m.text.range || monotype(), cmd = opt.edit; - as = opt.as = opt.as || as; - if(cmd && document.execCommand){ - r.restore(); - if(document.execCommand(cmd, null, as||null)){ - if(m.text.range){ m.text.range = monotype() } - return meta.flip(false); // ADDED meta.flip - } - } - if(!opt.tag){ return } - opt.tag = $(opt.tag); - opt.name = opt.name || opt.tag.prop('tagName'); - if((tmp = $(r.get()).closest(opt.name)).length){ - if(r.s === r.e){ - tmp.after(m.text.zws); - r = r.select(monotype.next(tmp[0]),1); - } else { - tmp.contents().unwrap(opt.name); - } - } else - if(r.s === r.e){ - r.insert(opt.tag); - r = r.select(opt.tag); - } else { - r.wrap(opt.tag); - } - r.restore(); - opt.range = null; - if(m.text.range){ m.text.range = monotype() } - } - meta.edit(meta.text.it = {combo: [-1], on: function(){ m.list(this, true) }, back: meta.edit}); // -1 is key for typing. - meta.text.it[-1] = meta.text.it; - meta.edit({ - name: "Bold", - combo: [-1,'B'], fake: -1, - on: function(eve){ - meta.text.editor('bold'); - }, - up: function(){} - }); - meta.edit({ - name: "Italic", - combo: [-1,'I'], fake: -1, - on: function(eve){ - meta.text.editor('italic'); - }, - up: function(){} - }); - /*meta.edit({ - name: "Underline", - combo: [-1,'U'], fake: -1, - on: function(eve){ - meta.text.editor('underline'); - }, - up: function(){} - });*/ - meta.edit({ - name: "linK", - combo: [-1,'K'], fake: -1, - on: function(eve){ - var range = meta.text.range || monotype(); - meta.ask('Paste or type link...', function(url){ - meta.text.editor({tag: $('link'), edit: url? 'createLink' : 'unlink', as: url, range: range}); - }) - } - }); - //meta.edit({name: "aliGn", combo: [-1,'G']}); // MOVE TO ADVANCED MENu! - meta.edit({ - name: "Left", - combo: [-1,'G','L'], fake: -1, - on: function(eve){ meta.text.editor('justifyLeft') }, - up: function(){} - }); - meta.edit({ - name: "Right", - combo: [-1,'G','R'], fake: -1, - on: function(eve){ meta.text.editor('justifyRight') }, - up: function(){ } - }); - meta.edit({ - name: "Middle", - combo: [-1,'G','M'], fake: -1, - on: function(eve){ meta.text.editor('justifyCenter') }, - up: function(){ } - }); - meta.edit({ - name: "Justify", - combo: [-1,'G','J'], fake: -1, - on: function(eve){ meta.text.editor('justifyFull') }, - up: function(){} - }); - // Align Number - // Align Points - // Align Strike - meta.edit({name: "Size", combo: [-1,'S'], on: function(){ m.list(this, true) }}); - meta.edit({ - name: "Small", - combo: [-1,'S','S'], fake: -1, - on: function(eve){ meta.text.editor('fontSize', 2) }, - up: function(){ } - }); - meta.edit({ - name: "Normal", - combo: [-1,'S','N'], fake: -1, - on: function(eve){ meta.text.editor('fontSize', 5) }, - up: function(){} - }); - meta.edit({ - name: "Header", - combo: [-1,'S','H'], fake: -1, - on: function(eve){ meta.text.editor('fontSize', 6) }, - up: function(){} - }); - meta.edit({ - name: "Title", - combo: [-1,'S','T'], fake: -1, - on: function(eve){ meta.text.editor('fontSize', 7) }, - up: function(){} - }); - - - })(USE, './metaText'); ;USE(function(module){ var m = meta, k = m.key; $(window).on('focus', k.wipe.bind(null, false)); // .on('blur', k.wipe.bind(null, false)) - //$(document).on('mousedown mousemove mouseup', function(eve){ - // m.tap.eve = eve; - // m.tap.x = eve.pageX||0; - // m.tap.y = eve.pageY||0; - // m.tap.on = $(eve.target); - //}) - // Setting m.tap.edit has been commented, so should never end up here? - //.on('mousedown touchstart', function(eve){ - // var tmp = m.tap.edit; - // if(!tmp || !tmp.on){ return } - // tmp.on(eve); - // m.tap.edit = null; - //}); - - //$(document).on('touchstart', '#meta .meta-start', function(eve){ m.tap.stun = true }); - + $(document).on('mousedown mousemove mouseup', function(eve){ + m.tap.eve = eve; + m.tap.x = eve.pageX||0; + m.tap.y = eve.pageY||0; + m.tap.on = $(eve.target); + }) var [start, end] = 'ontouchstart' in window ? ['touchstart', 'touchend'] : ['mousedown', 'mouseup'] - $(document).on(start, '#meta .meta-menu li', function(eve){ var combo = $(this).data().combo; - eve.fake = eve.which = combo && combo.slice(-1)[0].charCodeAt(0); + eve.fake = eve.which = combo && combo.slice(-1)[0].toUpperCase().charCodeAt(0); eve.tap = true; k.down(eve); $(document).one(end, () => k.up(eve)) return; - // if(m.tap.stun){ return m.tap.stun = false } - // if(!(eve.fake = eve.which = (($(this).text().match(/[A-Z]/)||{})[0]||'').toUpperCase().charCodeAt(0))){ return } - // eve.tap = true; - // k.down(eve); - // k.up(eve); }); $(document).on('keydown', k.down).on('keyup', k.up); - - $('#meta').on('click', function(ev) { + $('#meta').on(start, function(ev) { if (ev.target.tagName == 'LI' || ev.target.tagName == 'UL') return meta.flip() }) - - //$(document).on('select contextmenu keyup mouseup', '[contenteditable=true]', m.text.on); - - })(USE, './metaEvents'); }()); \ No newline at end of file