cloudcmd/modules/smalltalk/lib/smalltalk.js
2015-12-09 15:03:49 -05:00

221 lines
No EOL
7.4 KiB
JavaScript

'use strict';
(function (global) {
'use strict';
if (typeof module !== 'undefined' && module.exports) module.exports = SmallTalk();else global.smalltalk = SmallTalk();
function SmallTalk(callback) {
if (!(this instanceof SmallTalk)) return new SmallTalk(callback);
var remove = bind(removeEl, '.smalltalk');
var BUTTON_OK = ['OK'];
var BUTTON_OK_CANCEL = ['OK', 'Cancel'];
this.alert = function (title, msg, options) {
return showDialog(title, msg, '', BUTTON_OK, options);
};
this.prompt = function (title, msg, value, options) {
var val = value || '';
var valueStr = '<input type="text" value="' + val + '" data-name="js-input">';
return showDialog(title, msg, valueStr, BUTTON_OK_CANCEL, options);
};
this.confirm = function (title, msg, options) {
return showDialog(title, msg, '', BUTTON_OK_CANCEL, options);
};
function getTemplate(title, msg, value, buttons) {
if (!Array.isArray(buttons)) throw Error('buttons should be array!');
return '<div class="page">\n <div data-name="js-close" class="close-button"></div>\n <header>' + title + '</header>\n <div class="content-area">\n ' + msg + '\n ' + value + '\n </div>\n <div class="action-area">\n <div class="button-strip"> ' + buttons.map(function (name, i) {
return '<button tabindex=' + i + ' data-name="js-' + name.toLowerCase() + '">' + name + '</button>';
}).join('') + '\n </div>\n </div>\n </div>';
}
function showDialog(title, msg, value, buttons, options) {
var dialog = document.createElement('div'),
closeButtons = ['cancel', 'close', 'ok'],
ok = undefined,
cancel = undefined,
promise = new Promise(function (resolve, reject) {
var noCancel = options && !options.cancel;
var empty = function empty() {};
ok = resolve;
cancel = reject;
if (noCancel) cancel = empty;
}),
tmpl = getTemplate(title, msg, value, buttons);
dialog.innerHTML = tmpl;
dialog.className = 'smalltalk';
document.body.appendChild(dialog);
find(dialog, ['ok', 'input']).forEach(function (el) {
return el.focus();
});
find(dialog, ['input']).forEach(function (el) {
el.setSelectionRange(0, value.length);
});
addListeterAll('click', dialog, closeButtons, function (event) {
return closeDialog(event.target, dialog, ok, cancel);
});
['click', 'contextmenu'].forEach(function (event) {
return dialog.addEventListener(event, function () {
return find(dialog, ['ok', 'input']).forEach(function (el) {
return el.focus();
});
});
});
dialog.addEventListener('keydown', keyDown(dialog, ok, cancel));
return promise;
}
function keyDown(dialog, ok, cancel) {
return function (event) {
var KEY = {
ENTER: 13,
ESC: 27,
TAB: 9,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40
};
var keyCode = event.keyCode,
el = event.target;
var namesAll = ['ok', 'cancel', 'input'],
names = find(dialog, namesAll).map(function (el) {
return getDataName(el);
});
switch (keyCode) {
case KEY.ENTER:
closeDialog(el, dialog, ok, cancel);
event.preventDefault();
break;
case KEY.ESC:
remove();
cancel();
break;
case KEY.TAB:
if (event.shiftKey) tab(dialog, names);
tab(dialog, names);
event.preventDefault();
break;
default:
var is = ['left', 'right', 'up', 'down'].some(function (name) {
return keyCode === KEY[name.toUpperCase()];
});
if (is) changeButtonFocus(dialog, names);
break;
}
event.stopPropagation();
};
}
function getDataName(el) {
return el.getAttribute('data-name').replace('js-', '');
}
function changeButtonFocus(dialog, names) {
var name = '',
active = document.activeElement,
activeName = getDataName(active),
isButton = /ok|cancel/.test(activeName),
count = names.length - 1;
if (activeName !== 'input' && count && isButton) {
if (activeName === 'cancel') name = 'ok';else name = 'cancel';
find(dialog, [name]).forEach(function (el) {
return el.focus();
});
}
}
function tab(dialog, names) {
var active = document.activeElement,
activeName = getDataName(active),
count = names.length - 1,
index = names.indexOf(activeName);
if (index === count) index = 0;else if (index < count) ++index;
var name = names[index];
find(dialog, [name]).forEach(function (el) {
return el.focus();
});
}
function closeDialog(el, dialog, ok, cancel) {
var value = undefined,
name = el.getAttribute('data-name').replace('js-', '');
if (/close|cancel/.test(name)) {
cancel();
} else {
value = find(dialog, ['input']).reduce(function (value, el) {
return el.value;
}, null);
ok(value);
}
remove();
}
function find(element, names) {
var elements = names.map(function (name) {
return element.querySelector('[data-name="js-' + name + '"]');
}).filter(function (el) {
return el;
});
return elements;
}
function addListeterAll(event, parent, elements, fn) {
find(parent, elements).forEach(function (el) {
return el.addEventListener(event, fn);
});
}
function removeEl(name) {
var el = document.querySelector(name);
el.parentElement.removeChild(el);
}
function bind(fn) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
return function () {
return fn.apply(undefined, args);
};
}
}
})(typeof window !== 'undefined' && window);