You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

667 lines
13 KiB

/*
* Emoji plugin for summernote [https://github.com/summernote/summernote]
* Canonical - https://github.com/JustinEldracher/summernote-plugins
*/
odoo.define('muk_web_utils.summernote_ext_specialchars', function (require) {
'use strict';
//template
var tmpl = $.summernote.renderer.getTemplate();
// core functions: range, dom
var range = $.summernote.core.range;
var dom = $.summernote.core.dom;
var KEY = {
UP: 38,
DOWN: 40,
LEFT: 37,
RIGHT: 39,
ENTER: 13
};
var COLUMN_LENGTH = 15;
var COLUMN_WIDTH = 35;
var currentColumn, currentRow, totalColumn, totalRow = 0;
// special characters data set
var specialCharDataSet = [
"!",
""",
"#",
"$",
"%",
"&",
"'",
"(",
")",
"*",
"+",
",",
"-",
".",
"/",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
":",
"&#59;",
"<",
"=",
">",
"?",
"@",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"[",
"\",
"]",
"^",
"_",
"`",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"{",
"|",
"}",
"~",
"À",
"Á",
"Â",
"Ã",
"Ä",
"Å",
"Æ",
"Ç",
"È",
"É",
"Ê",
"Ë",
"Ì",
"Í",
"Î",
"Ï",
"Ð",
"Ñ",
"Ò",
"Ó",
"Ô",
"Õ",
"Ö",
"Ø",
"Ù",
"Ú",
"Û",
"Ü",
"Ý",
"Þ",
"ß",
"à",
"á",
"â",
"ã",
"ä",
"å",
"æ",
"ç",
"è",
"é",
"ê",
"ë",
"ì",
"í",
"î",
"ï",
"ð",
"ñ",
"ò",
"ó",
"ô",
"õ",
"ö",
"ø",
"ù",
"ú",
"û",
"ü",
"ý",
"þ",
"ÿ",
"¡",
"¢",
"£",
"¤",
"¥",
"¦",
"§",
"¨",
"©",
"ª",
"«",
"¬",
"®",
"¯",
"°",
"±",
"²",
"³",
"´",
"µ",
"¶",
"¸",
"¹",
"º",
"»",
"¼",
"½",
"¾",
"¿",
"×",
"÷",
"∀",
"∂",
"∃",
"∅",
"∇",
"∈",
"∉",
"∋",
"∏",
"∑",
"−",
"∗",
"√",
"∝",
"∞",
"∠",
"∧",
"∨",
"∩",
"∪",
"∫",
"∴",
"∼",
"≅",
"≈",
"≠",
"≡",
"≤",
"≥",
"⊂",
"⊃",
"⊄",
"⊆",
"⊇",
"⊕",
"⊗",
"⊥",
"⋅",
"Α",
"Β",
"Γ",
"Δ",
"Ε",
"Ζ",
"Η",
"Θ",
"Ι",
"Κ",
"Λ",
"Μ",
"Ν",
"Ξ",
"Ο",
"Π",
"Ρ",
"Σ",
"Τ",
"Υ",
"Φ",
"Χ",
"Ψ",
"Ω",
"α",
"β",
"γ",
"δ",
"ε",
"ζ",
"η",
"θ",
"ι",
"κ",
"λ",
"μ",
"ν",
"ξ",
"ο",
"π",
"ρ",
"ς",
"σ",
"τ",
"υ",
"φ",
"χ",
"ψ",
"ω",
"ϑ",
"ϒ",
"ϖ",
"Œ",
"œ",
"Š",
"š",
"Ÿ",
"ƒ",
"ˆ",
"˜",
" ",
" ",
" ",
"‌",
"‍",
"‎",
"‏",
"–",
"—",
"‘",
"’",
"‚",
"“",
"”",
"„",
"†",
"‡",
"•",
"…",
"‰",
"′",
"″",
"‹",
"›",
"‾",
"€",
"™",
"←",
"↑",
"→",
"↓",
"↔",
"↵",
"⌈",
"⌉",
"⌊",
"⌋",
"◊",
"♠",
"♣",
"♥",
"♦",
];
/**
* @member plugin.specialChar
* @private
* @param {jQuery} $editable
* @return {String}
*/
var getTextOnRange = function ($editable) {
$editable.focus();
var rng = range.create();
// if range on anchor, expand range with anchor
if (rng.isOnAnchor()) {
var anchor = dom.ancestor(rng.sc, dom.isAnchor);
rng = range.createFromNode(anchor);
}
return rng.toString();
};
/**
* Make Special Characters Table
*
* @member plugin.specialChar
* @private
* @return {jQuery}
*/
var makeSpecialCharSetTable = function () {
var $table = $("<div/>").attr("id", "specialCharTable");
$.each(specialCharDataSet, function (idx, text) {
var $block = $("<span/>").attr("style", "border:1px solid black;display:inline-block;height:50px;width:35px;text-align:center;font-size:14pt;color:black;padding-top:10px;cursor:pointer;")
.addClass("note-specialchar-node char-" + idx).attr("title", text).attr("id", "char-" + idx);
$block.append(text);
$table.append($block);
});
return $table;
};
/**
* Show Special Characters and set event handlers on dialog controls.
*
* @member plugin.specialChar
* @private
* @param {jQuery} $dialog
* @param {jQuery} $dialog
* @param {Object} text
* @return {Promise}
*/
var showSpecialCharDialog = function ($editable, $dialog, text) {
return $.Deferred(function (deferred) {
var $specialCharDialog = $dialog.find('.note-specialchar-dialog');
var $specialCharNode = $specialCharDialog.find('.note-specialchar-node');
var $selectedNode = null;
var ARROW_KEYS = [KEY.UP, KEY.DOWN, KEY.LEFT, KEY.RIGHT];
var ENTER_KEY = KEY.ENTER;
var pos = 0;
var end = specialCharDataSet.length;
function addActiveClass($target) {
if (!$target) {
return;
}
$target.find('span').addClass('active');
$selectedNode = $target;
}
function removeActiveClass($target) {
$target.find('span').removeClass('active');
$selectedNode = null;
}
// find next node
function findNextNode(row, column) {
var findNode = null;
$.each($specialCharNode, function (idx, $node) {
var findRow = Math.ceil((idx + 1) / COLUMN_LENGTH);
var findColumn = ((idx + 1) % COLUMN_LENGTH === 0) ? COLUMN_LENGTH : (idx + 1) % COLUMN_LENGTH;
if (findRow === row && findColumn === column) {
findNode = $node;
return false;
}
});
return $(findNode);
}
function arrowKeyHandler(keyCode) {
// left, right, up, down key
var w = $("#specialCharTable").css("width") + "";
w = w.substr(0, w.length - 2);
var cols = Math.floor(w / 35);
pos = parseInt(pos);
if (KEY.LEFT === keyCode) {
if (pos > 0) {
pos--;
clear();
$(".char-" + pos).css("border", "1px solid blue").css("background-color", "aliceblue");
$selectedNode = $(".char-" + pos);
}
} else if (KEY.RIGHT === keyCode) {
if (pos < end - 1) {
pos++;
clear();
$(".char-" + pos).css("border", "1px solid blue").css("background-color", "aliceblue");
$selectedNode = $(".char-" + pos);
}
} else if (KEY.UP === keyCode) {
if (pos - cols >= 0) {
clear();
pos = pos - cols;
$(".char-" + pos).css("border", "1px solid blue").css("background-color", "aliceblue");
$selectedNode = $(".char-" + pos);
}
} else if (KEY.DOWN === keyCode) {
if (pos + cols <= end) {
clear();
pos = pos + cols;
$(".char-" + pos).css("border", "1px solid blue").css("background-color", "aliceblue");
$selectedNode = $(".char-" + pos);
}
}
}
function enterKeyHandler() {
if (!$selectedNode) {
return;
}
pos = 0;
deferred.resolve(decodeURIComponent($selectedNode.attr("title")));
$specialCharDialog.modal('hide');
}
function keyDownEventHandler(event) {
event.preventDefault();
var keyCode = event.keyCode;
if (keyCode === undefined || keyCode === null) {
return;
}
// check arrowKeys match
if (ARROW_KEYS.indexOf(keyCode) > -1) {
arrowKeyHandler(keyCode);
} else if (keyCode === ENTER_KEY) {
enterKeyHandler();
}
return false;
}
// remove class
removeActiveClass($specialCharNode);
// find selected node
if (text) {
for (var i = 0; i < $specialCharNode.length; i++) {
var $checkNode = $($specialCharNode[i]);
if ($checkNode.text() === text) {
addActiveClass($checkNode);
currentRow = Math.ceil((i + 1) / COLUMN_LENGTH);
currentColumn = (i + 1) % COLUMN_LENGTH;
}
}
}
$specialCharDialog.one('shown.bs.modal', function () {
$(document).on('keydown', keyDownEventHandler);
$specialCharNode.on('click', function (event) {
event.preventDefault();
pos = 0;
deferred.resolve(decodeURIComponent(event.currentTarget.title));
$specialCharDialog.modal('hide');
});
$specialCharNode.mouseenter(function() {
clear();
$(this).css("border", "1px solid blue").css("background-color", "aliceblue");
$selectedNode = $(this);
var thisid = $(this).attr("id") + "";
pos = thisid.substr(5);
});
$specialCharNode.mouseleave(function() {
clear();
});
}).one('hidden.bs.modal', function () {
$specialCharNode.off('click');
$(document).off('keydown', keyDownEventHandler);
if (deferred.state() === 'pending') {
deferred.reject();
}
}).modal('show');
// tooltip
/*$dialog.find('span').tooltip({
container: $specialCharDialog.find('.form-group'),
trigger: 'hover',
placement: 'top'
});*/
// $editable blur
$editable.blur();
function clear() {
$specialCharNode.css("border", "1px solid black").css("background-color", "white");
$selectedNode = null;
}
});
};
/**
* @class plugin.specialChar
*
* Special Characters Plugin
*
* ### load script
*
* ```
* < script src="plugin/summernote-ext-specialchar.js"></script >
* ```
*
* ### use a plugin in toolbar
* ```
* $("#editor").summernote({
* ...
* toolbar : [
* ['group', [ 'specialChar' ]]
* ]
* ...
* });
* ```
*/
$.summernote.addPlugin({
/** @property {String} name name of plugin */
name: 'specialChar',
/**
* @property {Object} buttons
* @property {function(object): string} buttons.specialChar
*/
buttons: {
specialChar: function (lang, options) {
return tmpl.iconButton(options.iconPrefix + 'circle-o ' + options.iconPrefix, {
event: 'showSpecialCharDialog',
title: lang.specialChar.specialChar,
hide: true
});
}
},
/**
* @property {Object} dialogs
* @property {function(object, object): string} dialogs.specialChar
*/
dialogs: {
specialChar: function (lang) {
var body = '<div class="form-group row-fluid">' +
makeSpecialCharSetTable()[0].outerHTML +
'</div>';
return tmpl.dialog('note-specialchar-dialog', lang.specialChar.select, body);
}
},
/**
* @property {Object} events
* @property {Function} events.showSpecialCharDialog
*/
events: {
showSpecialCharDialog: function (event, editor, layoutInfo) {
var $dialog = layoutInfo.dialog(),
$editable = layoutInfo.editable(),
currentSpecialChar = getTextOnRange($editable);
// save current range
editor.saveRange($editable);
showSpecialCharDialog($editable, $dialog, currentSpecialChar).then(function (selectChar) {
// when ok button clicked
// restore range
editor.restoreRange($editable);
// build node
var $node = $('<span></span>').html(selectChar)[0];
//var $node = $(selectChar)[0];
if ($node) {
// insert character node
editor.insertNode($editable, $node);
}
}).fail(function () {
// when cancel button clicked
editor.restoreRange($editable);
});
}
},
// define language
langs: {
'en-US': {
specialChar: {
specialChar: 'Special Characters',
select: 'Select Special characters'
}
},
'ko-KR': {
specialChar: {
specialChar: '특수문자',
select: '특수문자를 선택하세요'
}
}
}
});
});