Skip to content

Instantly share code, notes, and snippets.

@imcuttle
Last active November 1, 2017 09:14
Show Gist options
  • Save imcuttle/30bd9df186cc01124be0e3239abaabe8 to your computer and use it in GitHub Desktop.
Save imcuttle/30bd9df186cc01124be0e3239abaabe8 to your computer and use it in GitHub Desktop.
snippet
/**
* @file: EventEmitter
* @author: Cuttle Cong
* @date: 2017/11/1
* @description:
*/
function assertType(type) {
if (typeof type !== 'string') {
throw new TypeError('type is not type of String!');
}
}
function assertFn(fn) {
if (typeof fn !== 'function') {
throw new TypeError('fn is not type of Function!');
}
}
function EventEmitter() {
this._events = {};
}
function on(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].push({
type: 'always',
fn: fn
});
}
function prepend(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].unshift({
type: 'always',
fn: fn
});
}
function prependOnce(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].unshift({
type: 'once',
fn
});
}
function once(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].push({
type: 'once',
fn
});
}
function off(type, nullOrFn) {
assertType(type);
if (!this._events[type]) return;
if (typeof nullOrFn === 'function') {
var index = this._events[type].findIndex(function (event) {
return event.fn === nullOrFn;
});
if (index >= 0) {
this._events[type].splice(index, 1);
}
} else {
delete this._events[type];
}
}
function emit(type, /* arguments */) {
assertType(type);
var args = [].slice.call(arguments, 1);
var self = this;
if (this._events[type]) {
this._events[type].forEach(function (event) {
event.fn.apply(null, args);
if (event.type === 'once') {
self.off(type, event.fn);
}
})
}
}
EventEmitter.prototype.on = EventEmitter.prototype.addListener = on;
EventEmitter.prototype.once = EventEmitter.prototype.addOnceListener = once;
EventEmitter.prototype.prepend = EventEmitter.prototype.prependListener = prepend;
EventEmitter.prototype.prependOnce = EventEmitter.prototype.prependOnceListener = prependOnce;
EventEmitter.prototype.off = EventEmitter.prototype.removeListener = off;
EventEmitter.prototype.emit = EventEmitter.prototype.trigger = emit;
if (typeof module !== 'undefined') {
module.exports = EventEmitter;
}
// ==UserScript==
// @name New Script
// @namespace Violentmonkey Scripts
// @match *://*/*/swagger-ui.html*
// @match *://*/swagger-ui.html*
// @grant none
// ==/UserScript==
window.addEventListener('load', function () {
/**
* @file: EventEmitter
* @author: Cuttle Cong
* @date: 2017/11/1
* @description:
*/
function assertType(type) {
if (typeof type !== 'string') {
throw new TypeError('type is not type of String!');
}
}
function assertFn(fn) {
if (typeof fn !== 'function') {
throw new TypeError('fn is not type of Function!');
}
}
function EventEmitter() {
this._events = {};
}
function on(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].push({
type: 'always',
fn: fn
});
}
function prepend(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].unshift({
type: 'always',
fn: fn
});
}
function prependOnce(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].unshift({
type: 'once',
fn
});
}
function once(type, fn) {
assertType(type);
assertFn(fn);
this._events[type] = this._events[type] || [];
this._events[type].push({
type: 'once',
fn
});
}
function off(type, nullOrFn) {
assertType(type);
if (!this._events[type]) return;
if (typeof nullOrFn === 'function') {
var index = this._events[type].findIndex(function (event) {
return event.fn === nullOrFn;
});
if (index >= 0) {
this._events[type].splice(index, 1);
}
} else {
delete this._events[type];
}
}
function emit(type, /* arguments */) {
assertType(type);
var args = [].slice.call(arguments, 1);
var self = this;
if (this._events[type]) {
this._events[type].forEach(function (event) {
event.fn.apply(null, args);
if (event.type === 'once') {
self.off(type, event.fn);
}
})
}
}
EventEmitter.prototype.on = EventEmitter.prototype.addListener = on;
EventEmitter.prototype.once = EventEmitter.prototype.addOnceListener = once;
EventEmitter.prototype.prepend = EventEmitter.prototype.prependListener = prepend;
EventEmitter.prototype.prependOnce = EventEmitter.prototype.prependOnceListener = prependOnce;
EventEmitter.prototype.off = EventEmitter.prototype.removeListener = off;
EventEmitter.prototype.emit = EventEmitter.prototype.trigger = emit;
if (typeof module !== 'undefined') {
module.exports = EventEmitter;
}
function KeyExtra(opt) {
this._init(opt);
}
KeyExtra.prototype = new EventEmitter();
KeyExtra.prototype.constructor = KeyExtra;
KeyExtra.prototype._init = function (opt) {
var keyExtra = this;
// double key press
var doublePressTimeoutMs = 600;
var lastKeypressTime = 0;
var lastKeyChar = null;
function doubleHandle(type) {
return function (evt) {
var thisCharCode = evt.key.toUpperCase();
if (lastKeyChar === null) {
lastKeyChar = thisCharCode;
lastKeypressTime = new Date();
return;
}
if (thisCharCode === lastKeyChar) {
var thisKeypressTime = new Date();
if (thisKeypressTime - lastKeypressTime <= doublePressTimeoutMs) {
keyExtra.emit('double-' + type, thisCharCode);
}
}
lastKeyChar = null;
lastKeypressTime = 0;
}
}
document && document.addEventListener('keypress', doubleHandle('keypress'));
document && document.addEventListener('keydown', doubleHandle('keydown'));
};
setTimeout(
function () {
(function($) {
if (typeof $ === 'undefined') {
console.error('jQuery is not found, so we consider that the page isn\'t swagger-ui.');
return;
}
if (typeof window.swaggerUi === 'undefined') {
console.error('window.swaggerUi is not defined, so we consider that the page isn\'t swagger-ui.');
return;
}
var dom = $('<div style="margin-top: 15px;"></div>');
dom.attr('class', 'inject-dom-container');
var btns = $('<div></div>');
btns.attr('class', 'inject-btn-container');
function listAll() {
$('.collapseResource').click();
}
function hideAll() {
$('.endpoints').css({display: 'none'});
}
function expendAll() {
$('.expandResource').click();
}
btns.append(
$('<button>List All</button>').on('click', listAll),
$('<button>Hide All</button>').on('click', hideAll),
$('<button>Expend All</button>').on('click', expendAll),
);
dom.append(btns);
dom.append([
'<div class="search-container" style="display: none;">',
'<div class="search-main">',
'<input class="search-input"/>',
'<ul class="search-found-list">',
'</ul>',
'</div>',
'</div>'
].join(''))
var searchContainer = dom.find('.search-container')
new KeyExtra()
.on('double-keydown', function (charCode) {
if (charCode === 'A' || charCode === 'SHIFT') {
setTimeout(function () {
$('body').css({overflow: 'hidden'});
searchContainer.show();
searchContainer.find('.search-input').focus().select();
}, 0)
}
});
function hideSearch() {
$('body').css({overflow: ''});
searchContainer.hide();
}
document.addEventListener('keydown', function (evt) {
if (evt.key === 'Escape') {
hideSearch();
}
})
var COUNT = 20;
function search(val) {
val = typeof val !== 'string' ? '' : val.trim();
if (!val) {
foundListDom.empty();
return;
}
var type = '';
if (/^(p|s|m): ([^]+)$/.test(val)) {
type = RegExp.$1;
val = RegExp.$2;
}
var keywords = val.split(/[+ ]/);
var foundList = [];
list.some(function (entity) {
if (foundList.length === 30) {
return true;
}
var matched_types = [];
var matched = keywords.every(function (keyword) {
function find(type, keyword) {
// console.log(entity);
if (entity[type].toLowerCase().includes(keyword.toLowerCase())) {
if (!matched_types.includes(type)) {
matched_types.push(type)
}
return true;
}
}
if (type) {
return find(type, keyword);
}
else {
return ['p', 's', 'm'].some(function (type) {
return find(type, keyword);
})
}
});
if (matched) {
foundList.push({
type: matched_types.join(' '),
entity: entity
});
}
});
foundListDom.empty();
function item(data, i) {
var html = '<li class="search-item ' + (i === 0 ? 'active' : '') + '">'
+ '<span class="search-item-type">' + data.type + '</span>'
+ ': '
+ '<span class="search-item-method">' + data.entity.m.toUpperCase() + '</span>'
+ ' '
+ '<span class="search-item-path">' + data.entity.p + '</span>'
+ '<span class="search-item-summary">' + data.entity.s + '</span>'
+ '</li>';
return $(html).on('click', function() {
var href = '#' + data.entity.url;
var link = $('.toggleOperation[href=' + JSON.stringify(href) + ']');
link.parents('ul.endpoints').css({display: 'block'});
link[0].scrollIntoView();
var operation = link.parents('.operation');
var content = operation.find('.content');
content.css('display') === 'none' && link[0].click();
hideSearch();
foundListDom.empty();
})
}
if (!foundList.length) {
foundListDom.append(
'<li class="search-item">' + 'Not Found :(' + '</li>'
);
}
else {
foundListDom.append(
foundList.map(item)
);
var sumHeight = 1;
var over = Array.from(foundListDom.children('.search-item')).some(function (dom, i) {
if (i === COUNT) {
return true;
}
sumHeight += $(dom).prop('clientHeight') + 1;
});
over && foundListDom.css({'max-height': sumHeight + 'px'})
}
}
var foundListDom = dom.find('.search-found-list');
dom.find('.search-input')
.on('input', function (evt) { search(evt.target.value) })
.on('focus', function (evt) { search(evt.target.value) })
// .on('blur', function (evt) { setTimeout(function () {foundListDom.empty()}, 300) })
.on('keydown', function (evt) {
var activeIndex = null;
var listDoms = foundListDom.find('.search-item');
function findActive() {
Array.from(listDoms).some(function (dom, i){
if ($(dom).hasClass('active')) {
$(dom).removeClass('active');
activeIndex = i;
}
});
}
var crlKey = evt.metaKey || evt.ctrlKey;
var offset = crlKey ? COUNT : 1;
var isUp = null;
var prevIndex = activeIndex;
switch (evt.keyCode) {
case 38: // UP
findActive();
activeIndex = (listDoms.length + activeIndex - offset) % listDoms.length;
listDoms.eq(activeIndex).addClass('active');
isUp = true;
break;
case 40: // DOWN
findActive();
activeIndex = (activeIndex + offset) % listDoms.length
listDoms.eq(activeIndex).addClass('active');
isUp = false;
break;
case 13: // ENTER
findActive();
listDoms[activeIndex] && listDoms[activeIndex].click();
return;
}
if (isUp === null) {
return;
}
evt.preventDefault();
var rang = [foundListDom.prop('scrollTop'), foundListDom.prop('scrollTop') + foundListDom.prop('clientHeight') - 10]
// console.log(rang, listDoms[activeIndex].offsetTop)
// console.dir(foundListDom[0])
// console.log('!', listDoms[activeIndex].offsetTop, rang);
if (listDoms[activeIndex]) {
if (!(listDoms[activeIndex].offsetTop >= rang[0] && listDoms[activeIndex].offsetTop <= rang[1])) {
// debugger;
if (activeIndex === 0) {
foundListDom[0].scrollTop = 0;
} else if (activeIndex === listDoms.length - 1) {
foundListDom[0].scrollTop = foundListDom.prop('scrollHeight');
} else {
foundListDom[0].scrollTop += isUp ? -foundListDom.prop('clientHeight') : foundListDom.prop('clientHeight');
}
}
}
//console.dir(foundListDom[0])
//console.dir(listDoms[activeIndex]);
})
var list = [];
var url = window.swaggerUi.api && window.swaggerUi.api.url;
if (url) {
$.getJSON(url, function(data) {
// console.log(data);
$.each(data.paths, function (path, methodSet) {
$.each(methodSet, function (method, methodEntity) {
// @todo:: array ??
methodEntity.tags.join(',')
methodEntity.operationId
methodEntity.summary
list.push({
methodEntity: methodEntity,
url: '!/' + methodEntity.tags.join(',') + '/' + methodEntity.operationId,
s: methodEntity.summary,
m: method,
p: path
})
})
})
})
}
dom.insertAfter($('#header'));
$('head').append(
'<style type="text/css">'
+ '.inject-btn-container {'
+ 'text-align: center;'
+ '}'
+ '.inject-btn-container button {'
+ 'margin-left: 5px;'
+ 'margin-right: 5px;'
+ '}'
+ '.search-item-type{'
+ 'display: inline-block;'
+ 'min-width: 15px;'
+ '}'
+ '.search-item-method {'
+ 'display: inline-block;'
+ 'width: 65px;'
+ 'text-align: center'
+ '}'
+ '.search-item-summary {'
+ 'display: inline-block;'
+ 'width: auto;'
+ 'float: right;'
+ 'max-width: 200px;'
+ 'overflow: hidden;'
+ 'text-overflow: ellipsis;'
+ 'white-space: nowrap;'
+ 'text-align: right;'
+ '}'
+ '.search-main {'
+ 'position: static;'
+ 'margin: 40px auto 40px;'
+ 'width: 68%;'
+ 'min-width: 500px;'
+ '}'
+ '.search-container {'
+ 'overflow-y: auto;'
+ 'background-color: rgba(0, 0, 0, .3);'
+ 'position: fixed;'
+ 'left: 0;'
+ 'right: 0;'
+ 'top: 0;'
+ 'bottom: 0;'
+ '}'
+ '.search-input {'
+ 'display: block;'
+ 'margin: auto;'
+ 'width: 100%;'
+ 'border: none;'
+ 'border-bottom: 1px solid #89bf04;'
+ 'padding: 4px 10px 2px;'
+ 'box-sizing: border-box;'
+ '}'
+ '.search-input:focus {'
+ 'outline: none;'
+ '}'
+ '.search-found-list {'
+ 'position: static;'
+ 'left: 0;'
+ 'right: 0;'
// + 'max-height: 200px;'
+ 'overflow: auto;'
+ ''
+ '}'
+ '.search-found-list {'
+ 'margin-top: 2px;'
+ 'list-style: none;'
+ '}'
+ '.search-item.active, .search-item:hover {'
+ 'background-color: #eee;'
+ '}'
+ '.search-item {'
+ 'cursor: pointer;'
+ 'background-color: #fff;'
+ 'padding: 7px 15px;'
+ 'border: 1px solid #333;'
+ 'border-bottom: none;'
+ '}'
+ '.search-item:last-child {'
+ 'border-bottom: 1px solid #333;'
+ '}'
+ '</style>'
)
// auto scrollIntoView by hash
setTimeout(function () {
var a = $('a[href="' + location.hash + '"]')[0];
a && a.scrollIntoView();
}, 200);
})(window.jQuery)
},
1000
)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment