aboutsummaryrefslogtreecommitdiff
path: root/static/js
diff options
context:
space:
mode:
authorLibravatar bai 2019-03-29 02:14:43 +0000
committerLibravatar bai 2019-03-29 02:14:43 +0000
commit95dfe14528663923ca2a88ec928f1d8d9df2402b (patch)
tree5bc88d1466957f1aa39043b056bde5c439648022 /static/js
downloadweabot-95dfe14528663923ca2a88ec928f1d8d9df2402b.tar.gz
weabot-95dfe14528663923ca2a88ec928f1d8d9df2402b.tar.xz
weabot-95dfe14528663923ca2a88ec928f1d8d9df2402b.zip
Init
Diffstat (limited to 'static/js')
-rw-r--r--static/js/aquiencitas.js168
-rw-r--r--static/js/autorefresh.js275
-rw-r--r--static/js/home.js173
-rw-r--r--static/js/jquery.js545
-rw-r--r--static/js/manage.js22
-rw-r--r--static/js/mobile.js447
-rw-r--r--static/js/paintbbs/PaintBBS-1.1.11.css535
-rw-r--r--static/js/paintbbs/PaintBBS-1.1.11.js5686
-rw-r--r--static/js/paintbbs/PaintBBS-1.3.4.css547
-rw-r--r--static/js/paintbbs/PaintBBS-1.3.4.js6171
-rwxr-xr-xstatic/js/palette_selfy.js972
-rw-r--r--static/js/shobon.js408
-rw-r--r--static/js/tegaki/tegaki.css187
-rw-r--r--static/js/tegaki/tegaki.js1947
-rw-r--r--static/js/weabot.js456
-rw-r--r--static/js/weabotxt.js299
-rw-r--r--static/js/wpaint/.gitignore3
-rw-r--r--static/js/wpaint/README.md421
-rw-r--r--static/js/wpaint/bai.js23
-rw-r--r--static/js/wpaint/demo/demo.css266
-rw-r--r--static/js/wpaint/demo/img/facebook-icon.pngbin0 -> 274 bytes
-rw-r--r--static/js/wpaint/demo/img/favicon.icobin0 -> 1150 bytes
-rw-r--r--static/js/wpaint/demo/img/forkme_right_darkblue.pngbin0 -> 7791 bytes
-rw-r--r--static/js/wpaint/demo/img/github-icon.pngbin0 -> 596 bytes
-rw-r--r--static/js/wpaint/demo/img/googleplus-icon.pngbin0 -> 522 bytes
-rw-r--r--static/js/wpaint/demo/img/linkedin-icon.pngbin0 -> 380 bytes
-rw-r--r--static/js/wpaint/demo/img/rss-icon.pngbin0 -> 521 bytes
-rw-r--r--static/js/wpaint/demo/img/stumbleupon-icon.pngbin0 -> 537 bytes
-rw-r--r--static/js/wpaint/demo/img/twitter-icon.pngbin0 -> 514 bytes
-rw-r--r--static/js/wpaint/demo/img/websanova-logo-small-full-black.pngbin0 -> 1028 bytes
-rw-r--r--static/js/wpaint/demo/img/youtube-icon.pngbin0 -> 587 bytes
-rw-r--r--static/js/wpaint/gruntfile.js90
-rw-r--r--static/js/wpaint/index.html136
-rw-r--r--static/js/wpaint/lib/jquery.1.10.2.min.js6
-rw-r--r--static/js/wpaint/lib/jquery.ui.core.1.10.3.min.js4
-rw-r--r--static/js/wpaint/lib/jquery.ui.draggable.1.10.3.min.js4
-rw-r--r--static/js/wpaint/lib/jquery.ui.mouse.1.10.3.min.js4
-rw-r--r--static/js/wpaint/lib/jquery.ui.widget.1.10.3.min.js4
-rw-r--r--static/js/wpaint/lib/mixins.styl7
-rw-r--r--static/js/wpaint/lib/wColorPicker.min.css42
-rw-r--r--static/js/wpaint/lib/wColorPicker.min.js2
-rw-r--r--static/js/wpaint/package.json25
-rw-r--r--static/js/wpaint/plugins/file/img/icons-menu-main-file.pngbin0 -> 835 bytes
-rw-r--r--static/js/wpaint/plugins/file/src/wPaint.menu.main.file.js75
-rw-r--r--static/js/wpaint/plugins/file/wPaint.menu.main.file.min.js1
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-bucket.pngbin0 -> 450 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-crosshair.pngbin0 -> 208 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-dropper.pngbin0 -> 403 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser1.pngbin0 -> 193 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser10.pngbin0 -> 247 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser2.pngbin0 -> 200 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser3.pngbin0 -> 206 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser4.pngbin0 -> 209 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser5.pngbin0 -> 225 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser6.pngbin0 -> 229 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser7.pngbin0 -> 236 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser8.pngbin0 -> 240 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-eraser9.pngbin0 -> 244 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/cursor-pencil.pngbin0 -> 449 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/icon-group-arrow.pngbin0 -> 208 bytes
-rw-r--r--static/js/wpaint/plugins/main/img/icons-menu-main.pngbin0 -> 2836 bytes
-rw-r--r--static/js/wpaint/plugins/main/src/fillArea.min.js1
-rw-r--r--static/js/wpaint/plugins/main/src/wPaint.menu.main.js338
-rw-r--r--static/js/wpaint/plugins/main/wPaint.menu.main.min.js1
-rw-r--r--static/js/wpaint/plugins/shapes/img/icons-menu-main-shapes.pngbin0 -> 903 bytes
-rw-r--r--static/js/wpaint/plugins/shapes/src/shapes.min.js1
-rw-r--r--static/js/wpaint/plugins/shapes/src/wPaint.menu.main.shapes.js207
-rw-r--r--static/js/wpaint/plugins/shapes/wPaint.menu.main.shapes.min.js1
-rw-r--r--static/js/wpaint/plugins/text/img/icons-menu-text.pngbin0 -> 802 bytes
-rw-r--r--static/js/wpaint/plugins/text/src/wPaint.menu.text.js227
-rw-r--r--static/js/wpaint/plugins/text/wPaint.menu.text.min.js1
-rw-r--r--static/js/wpaint/src/wPaint.css348
-rw-r--r--static/js/wpaint/src/wPaint.js1181
-rw-r--r--static/js/wpaint/src/wPaint.utils.js70
-rw-r--r--static/js/wpaint/test/dev.html123
-rw-r--r--static/js/wpaint/test/fullscreen.html79
-rw-r--r--static/js/wpaint/test/upload.php11
-rw-r--r--static/js/wpaint/test/uploads/test1.pngbin0 -> 432 bytes
-rw-r--r--static/js/wpaint/test/uploads/test2.pngbin0 -> 462 bytes
-rw-r--r--static/js/wpaint/test/uploads/test3.pngbin0 -> 454 bytes
-rw-r--r--static/js/wpaint/test/uploads/wPaint.pngbin0 -> 3096 bytes
-rw-r--r--static/js/wpaint/wPaint.jquery.json38
-rw-r--r--static/js/wpaint/wPaint.min.css66
-rw-r--r--static/js/wpaint/wPaint.min.js1
84 files changed, 22645 insertions, 0 deletions
diff --git a/static/js/aquiencitas.js b/static/js/aquiencitas.js
new file mode 100644
index 0000000..0cf860f
--- /dev/null
+++ b/static/js/aquiencitas.js
@@ -0,0 +1,168 @@
+var cur_url;
+var linklist;
+var linki;
+var is_bbs;
+var plimit = 5;
+function getPostRange(t, n) {
+ var posts, replies, s, ss, ee, rev = false;
+ posts = [];
+ replies = t.getElementsByClassName("reply");
+ s = n.split('-');
+ ss = parseInt(s[0]);
+ ee = ss;
+ if(s.length == 2) ee = parseInt(s[1]);
+ if(ee<ss) { tmp=ss;ss=ee;ee=tmp; rev=true; }
+ for(j = 0; j < replies.length; j++) {
+ num = parseInt(replies[j].dataset.n);
+ if(num > ee) break;
+ if(num >= ss && num <= ee) {
+ if(rev) posts.unshift(replies[j]);
+ else posts.push(replies[j]);
+ }
+ }
+ return posts;
+}
+function findAncestor (el) {
+ while ((el = el.parentElement) && !el.className.startsWith("thread") && !el.className.startsWith("cont"));
+ return el;
+}
+function getPostDivs(e) {
+ if(is_bbs) {
+ divs = [];
+ t = findAncestor(e);
+ s = e.getAttribute('href').split('/');
+ r = s[s.length-1];
+ rs = r.split(',');
+ linki = 0;
+ for(i=0;i<rs.length;i++) { divs.push.apply(divs, getPostRange(t, rs[i])); }
+ return divs;
+ } else {
+ ele = document.getElementById('reply' + e.getAttribute('href').split('#')[1]);
+ return [ele,];
+ }
+}
+function get_pid(e) {
+ return is_bbs ? e.dataset.n : e.id.substr(5);
+}
+function fill_links(e) {
+ var divs = getPostDivs(e);
+ if(!divs[0]) return;
+
+ this_id = get_pid(e.parentNode.parentNode);
+
+ for(i=0;i<divs.length;i++) {
+ tid = get_pid(divs[i]);
+ if (linklist[tid])
+ continue;
+ if (this_id == tid)
+ continue;
+ t = (is_bbs ? divs[i].getElementsByTagName("h4")[0] : divs[i]);
+ bl = document.createElement('a');
+ bl.href = cur_url + (is_bbs ? "/" : "#") + this_id;
+ bl.textContent = '>>' + this_id;
+ bl.addEventListener('mouseover', who_are_you_quoting, false);
+ bl.addEventListener('mouseout', remove_quote_preview, false);
+ if (!(qb = t.getElementsByClassName('quoted')[0])) {
+ qb = document.createElement((is_bbs ? 'span' : 'div'));
+ qb.className = 'quoted';
+ qb.textContent = ' Citado por: ';
+ if(is_bbs) {
+ t.insertBefore(qb, t.getElementsByClassName("del")[0]);
+ t.insertBefore(document.createTextNode(' '), t.getElementsByClassName("del")[0]);
+ } else {
+ p = t.getElementsByTagName("blockquote");
+ p[p.length-1].insertAdjacentHTML('afterend', qb.outerHTML);
+ }
+ t.getElementsByClassName('quoted')[0].appendChild(bl);
+ } else {
+ qb.appendChild(document.createTextNode(' '));
+ qb.appendChild(bl);
+ }
+ linklist[tid] = true;
+ }
+}
+function who_are_you_quoting(e) {
+ var parent, d, clr, src, cnt, left, top, width, maxWidth;
+ e = e.target || window.event.srcElement;
+ var divs = getPostDivs(e);
+ if(!divs[0]) return;
+
+ maxWidth = 500;
+ cnt = document.createElement('div');
+ cnt.id = 'q-p';
+ width = divs[0].offsetWidth;
+ if (width > maxWidth) {
+ width = maxWidth;
+ }
+
+ for(i=0;i<divs.length&&i<plimit;i++) {
+ src = divs[i].cloneNode(true);
+ cnt.appendChild(src);
+ }
+ left = 0;
+ top = e.offsetHeight + 1;
+ parent = e;
+ do {
+ left += parent.offsetLeft;
+ top += parent.offsetTop;
+ } while (parent = parent.offsetParent);
+ if ((d = document.body.offsetWidth - left - width) < 0) left += d;
+ cnt.setAttribute('style', 'left:' + left + 'px;top:' + top + 'px;');
+ document.body.appendChild(cnt);
+}
+function remove_quote_preview(e) {
+ var cnt;
+ if (cnt = document.getElementById('q-p'))
+ document.body.removeChild(cnt);
+}
+/*function goTo(e) {
+ e.preventDefault();
+ var pst = this.textContent.split(/[-,]/)[0];
+ pst = "r"+ pst.slice(2);
+ pst = document.getElementById(pst);
+ if (pst) pst.scrollIntoView();
+}*/
+function quotePreview() {
+ if(localStorage.getItem("shobon_on") == "false") { return; }
+ if(localStorage.getItem("shobon_preview") == "false" && localStorage.getItem("shobon_backlink") == "false") { return; }
+
+ var i, q, replies, quotes;
+
+ if(document.body.className && document.body.className != "res")
+ is_bbs = true;
+ else is_bbs = false;
+
+ if(is_bbs) replies = document.getElementsByClassName('msg');
+ else replies = document.getElementsByTagName('blockquote');
+
+ urls = window.location.pathname.split("/");
+ cur_url = urls[0] + "/" + urls[1] + "/" + urls[2] + "/" + urls[3];
+
+ for (x = 0; x < replies.length; x++) {
+ quotes = replies[x].getElementsByTagName('a');
+ linklist = {};
+
+ for (i = 0; i < quotes.length; i++) {
+ q = quotes[i];
+ if(q.textContent.length < 3 || !q.textContent.startsWith(">>")) continue;
+
+ if(localStorage.getItem("shobon_preview") != "false") {
+ q.addEventListener('mouseover', who_are_you_quoting, false);
+ q.addEventListener('mouseout', remove_quote_preview, false);
+ }
+
+ if(localStorage.getItem("shobon_backlink") != "false") {
+ fill_links(q);
+ }
+ }
+ }
+/* if (document.body.className === "threadpage") {
+ for (x = 0; x < replies.length; x++) {
+ var q = replies[x].getElementsByTagName("a");
+ for(var j=0;j<q.length;j++) {
+ if(q[j].textContent.startsWith(">>")) q[j].addEventListener("click", goTo, false);
+ }
+ }
+ }*/
+}
+document.addEventListener('DOMContentLoaded', quotePreview, false); \ No newline at end of file
diff --git a/static/js/autorefresh.js b/static/js/autorefresh.js
new file mode 100644
index 0000000..0ed3e06
--- /dev/null
+++ b/static/js/autorefresh.js
@@ -0,0 +1,275 @@
+var lastTime = 0;
+var refreshInterval;
+var refreshMaxTime = 30;
+var refreshTime;
+var manual = 0;
+var serviceType = 0; // 2 = BBS, 3 = IB
+var thread_length = 0;
+var thread_lastreply = 0;
+var thread_title = "";
+var thread_first_length = 0;
+var http_request = new XMLHttpRequest();
+
+function checkNew(e) {
+ e.preventDefault();
+ manual = 1;
+ loadJSON();
+ if (chk.checked) refreshMaxTime = 25;
+}
+
+function loadJSON() {
+ if (chk.checked)
+ stopCounter("...");
+ if (manual)
+ document.getElementById("counter").innerText = "...";
+ var data_file;
+ if (serviceType == 2 || serviceType == 3) {
+ board = document.getElementsByName("board")[0].value;
+ parent = document.getElementsByName("parent")[0].value;
+ data_file = "/cgi/api/thread?dir=" + board + "&id=" + parent + "&offset=" + thread_length + "&time=" + lastTime;
+ } else {
+ return false;
+ }
+ http_request.open("GET", data_file, true);
+ http_request.send();
+}
+
+function updateThread(posts, total_replies, serverTime) {
+ thread_div = document.getElementsByClassName("thread")[0];
+ if (serviceType == 2)
+ last_elem = document.getElementsByClassName("size")[0];
+ else
+ last_elem = document.getElementsByClassName("cut")[0];
+
+ for (var i = 0; i < posts.length; i++) {
+ post = posts[i];
+ var div = document.createElement('div');
+ if (serviceType == 2) div.className = "reply";
+ else div.className = "replycont";
+ if (post.email) {
+ if (post.tripcode) s_name = '<a href="mailto:' + post.email + '"><span class="name"><b>' + post.name + '</b> ' + post.tripcode + '</span></a>';
+ else s_name = '<a href="mailto:' + post.email + '"><span class="name"><b>' + post.name + '</b></span></a>';
+ } else {
+ if (post.tripcode) s_name = '<span class="name"><b>' + post.name + '</b> ' + post.tripcode + '</span>';
+ else s_name = '<span class="name"><b>' + post.name + '</b></span>';
+ }
+ if (serviceType == 2) {
+ if (post.file) {
+ s_img = '<a href="/' + board + '/src/' + post.file + '" target="_blank" class="thumb"><img src="/' + board + '/thumb/' + post.thumb + '" width="' + post.thumb_width + '" height="' + post.thumb_height + '" /><br />' + Math.round(post.file_size/1024) + 'KB ' + post.file.substring(post.file.lastIndexOf(".")+1, post.file.length).toUpperCase() + '</a>';
+ } else s_img = '';
+ if (post.IS_DELETED == 1) div.innerHTML = '<h4 class="deleted">' + (thread_length + i + 1) + ' : Mensaje eliminado por el usuario.</h4>';
+ else if (post.IS_DELETED == 2) div.innerHTML = '<h4 class="deleted">' + (thread_length + i + 1) + ' : Mensaje eliminado por miembro del staff.</h4>';
+ else
+ div.innerHTML = '<h4>' + (thread_length + i + 1) + ' : ' + s_name + ' : <span class="date" data-unix="' + post.timestamp + '">' + post.timestamp_formatted + '</span> <span class="del"><a href="/cgi/report/' + board + '/' + post.id + '/' + (thread_length + i + 1) + '" rel="nofollow">rep</a> <a href="#">del</a></span></h4>' + s_img + '<div class="msg">' + post.message + '</div>';
+ } else {
+ if (post.file) {
+ if (post.image_width != 0) {
+ s_img = '<div class="fs"><a href="/' + board + '/src/' + post.file + '" class="expimg" data-id="' + post.id + '" data-thumb="/' + board + '/thumb/' + post.thumb + '" data-w="' + post.image_width + '" data-h="' + post.image_height + '" data-tw="' + post.thumb_width + '" data-th="' + post.thumb_height + '">' + post.file + '</a>-(' + post.file_size+ ' B, ' + post.image_width + 'x' + post.image_height + ')</div>';
+ } else {
+ s_img = '<div class="fs"><a href="/' + board + '/src/' + post.file + '" target="_blank">' + post.file + '</a>-(' + post.file_size+ ' B)</div>';
+ }
+ s_img += '<a target="_blank" href="/' + board + '/src/' + post.file + '" id="thumb' + post.id + '"><img class="thumb" alt="' + post.id + '" src="/' + board + '/thumb/' + post.thumb + '" width="' + post.thumb_width + '" height="' + post.thumb_height + '" /></a>';
+ s_msg = '<blockquote style="margin-left:' + (post.thumb_width+40) + 'px;">' + post.message + '</blockquote>';
+ } else {
+ s_img = '';
+ s_msg = '<blockquote>' + post.message + '</blockquote>';
+ }
+ if (post.IS_DELETED == 0) {
+ div.innerHTML = '<table border="0"><tr><td class="ell">…</td><td class="reply" id="reply' + post.id + '"><div class="info"><input type="checkbox" name="delete" value="' + post.id + '" />' + (post.subject ? (' <span class="subj">' + post.subject + '</span>') : '') + ' ' + s_name + ' ' + '<span class="date" data-unix="' + post.timestamp + '">' + post.timestamp_formatted + '</span> <span class="reflink"><a href="#' + post.id + '">No.</a><a href="#" class="postid">' + post.id + '</a></span> <a class="rep" href="/cgi/report/' + board + '/' + post.id + '" rel="nofollow">rep</a></div>' + s_img + s_msg + '</td></tr></table>';
+ }
+ }
+
+ thread_div.insertBefore(div, last_elem);
+ thread_div.setAttribute("data-length",(thread_length + i + 1));
+ if (serviceType == 2)
+ document.getElementsByTagName("h3")[0].getElementsByTagName("span")[0].innerText = "(" + (thread_length + i + 1) + " respuestas)";
+ }
+
+ if (posts.length > 0) {
+ if (!manual)
+ refreshMaxTime = 10;
+ if (!document.hasFocus())
+ if (posts.length > 1)
+ notif(thread_title, posts.length + ' nuevos mensajes');
+ else
+ notif(thread_title, 'Un nuevo mensaje');
+ } else {
+ if (refreshMaxTime <= 60)
+ refreshMaxTime += 5;
+ }
+
+ thread_length = parseInt(total_replies) + 1;
+ //document.getElementsByClassName("thread")[0].firstChild.children[0].innerHTML = "("+thread_length+")";
+ new_unread = thread_length - thread_first_length;
+
+ if (new_unread)
+ document.title = "(" + new_unread + ") " + thread_title;
+ else
+ document.title = thread_title;
+}
+
+function notif(title, msg) {
+ var n = new Notification(title, {
+ body: msg
+ });
+ setTimeout(n.close.bind(n), 10000);
+}
+
+function counter() {
+ if (refreshTime < 1) {
+ loadJSON();
+ } else {
+ refreshTime--;
+ document.getElementById("counter").innerHTML = (refreshTime + 1);
+ }
+}
+
+function detectService() {
+ if (document.body.className === "threadpage") {
+ if (!document.getElementById("n")) return;
+ thread_title = document.title;
+ thread_length = parseInt(document.getElementsByClassName("thread")[0].dataset.length);
+ thread_first_length = thread_length;
+ replylist = document.getElementsByClassName("reply");
+ lastr = replylist[replylist.length - 1].textContent;
+ thread_lastreply = parseInt(lastr.substr(0, lastr.indexOf(" :")));
+ if (thread_length == thread_lastreply) {
+ serviceType = 2;
+ document.getElementById("n").addEventListener("click", checkNew);
+ var footer = document.getElementsByClassName("lastposts")[0];
+ var in1 = document.createElement("input");
+ in1.id = "autorefresh";
+ in1.setAttribute("type", "checkbox");
+ in1.addEventListener("click", autoRefresh);
+ in1.style.display = "none";
+ var in2 = document.createElement("label");
+ in2.id = "n2";
+ in2.setAttribute("for", "autorefresh");
+ in2.style.marginRight = "4px";
+ in2.style.cursor = "pointer";
+ in2.textContent = "Auto refresh";
+ var in3 = document.createElement("span");
+ in3.id = "counter";
+ in3.style.position = "absolute";
+ in3.textContent = "OFF";
+ footer.appendChild(document.createTextNode(" | "));
+ footer.appendChild(in1);
+ footer.appendChild(in2);
+ footer.appendChild(in3);
+ return true;
+ } else {
+ return false;
+ }
+ } else if (document.body.className === "res") {
+ serviceType = 3;
+ thread_title = document.title;
+ thread_length = parseInt(document.getElementsByClassName("thread")[0].dataset.length);
+ thread_first_length = thread_length;
+ replylist = document.getElementsByClassName("thread");
+ replylist += document.getElementsByClassName("reply");
+ var footer = document.getElementsByClassName("nav")[0];
+ var mnl = document.createElement("a");
+ mnl.id = "shownew";
+ mnl.href = "#";
+ mnl.textContent = "Ver nuevos posts";
+ var in1 = document.createElement("input");
+ in1.id = "autorefresh";
+ in1.setAttribute("type", "checkbox");
+ in1.addEventListener("click", autoRefresh);
+ in1.style.display = "none";
+ var in2 = document.createElement("label");
+ in2.setAttribute("for", "autorefresh");
+ in2.style.cursor = "pointer";
+ in2.title = "Ver nuevos posts automáticamente";
+ in2.textContent = "Auto";
+ var in4 = document.createElement("span");
+ in4.id = "counter";
+ in4.textContent = "OFF";
+ footer.appendChild(document.createTextNode(" ["));
+ footer.appendChild(mnl);
+ document.getElementById("shownew").addEventListener("click", checkNew);
+ footer.appendChild(document.createTextNode("] ["));
+ footer.appendChild(in1);
+ footer.appendChild(in2);
+ footer.appendChild(document.createTextNode("] "));
+ footer.appendChild(in4);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+function startCounter() {
+ refreshTime = refreshMaxTime;
+ counter();
+ refreshInterval = setInterval(counter, 1000);
+}
+
+function stopCounter(str) {
+ clearInterval(refreshInterval);
+ document.getElementById("counter").innerHTML = str;
+}
+
+function autoRefresh(e) {
+ chk_snd = document.getElementById("autosound");
+ if (document.getElementById("autorefresh").checked) {
+ if (chk_snd)
+ chk_snd.disabled = false;
+ Notification.requestPermission();
+ lastTime = Math.floor(Date.now() / 1000);
+ refreshTime = refreshMaxTime;
+ startCounter();
+ } else {
+ if (chk_snd)
+ document.getElementById("autosound").disabled = true;
+ stopCounter("OFF");
+ }
+}
+
+http_request.onreadystatechange = function() {
+ if (http_request.readyState == 4) {
+ var jsonObj = JSON.parse(http_request.responseText);
+ if (jsonObj.state == "success") {
+ if (serviceType == 2 || serviceType == 3)
+ updateThread(jsonObj.posts, jsonObj.total_replies, jsonObj.time);
+ lastTime = jsonObj.time;
+ if (chk.checked)
+ startCounter();
+ }
+ if (!chk.checked) {
+ document.getElementById("counter").innerText = "OFF";
+ }
+ manual = 0;
+ }
+}
+document.addEventListener("DOMContentLoaded", function() {
+ if (!detectService()) return;
+
+ chk = document.getElementById("autorefresh");
+ chk_snd = document.getElementById("autosound");
+
+ if (localStorage.getItem("autorefresh")) {
+ document.getElementById("autorefresh").checked = true;
+ autoRefresh();
+ }
+ if (!chk_snd) return;
+ if (localStorage.getItem("mainpage_nosound"))
+ document.getElementById("autosound").checked = false;
+});
+
+window.addEventListener("unload", function() {
+ if (!serviceType) return;
+
+ chk = document.getElementById("autorefresh");
+ chk_snd = document.getElementById("autosound");
+
+ if (chk.checked)
+ localStorage.setItem("autorefresh", true);
+ else
+ localStorage.removeItem("autorefresh");
+ if (!chk_snd) return;
+ if (!document.getElementById("autosound").checked)
+ localStorage.setItem("mainpage_nosound", true);
+ else
+ localStorage.removeItem("mainpage_nosound");
+}); \ No newline at end of file
diff --git a/static/js/home.js b/static/js/home.js
new file mode 100644
index 0000000..0c921ec
--- /dev/null
+++ b/static/js/home.js
@@ -0,0 +1,173 @@
+console.log("%c¡Es calidad BaI!", "font-size: 50px; font-weight: bold;");
+
+function set_stylesheet(styletitle) {
+ opcs.style = styletitle;
+ parse();
+ var links=document.getElementsByTagName("link");
+ var found=false;
+ for(var i=0;i<links.length;i++) {
+ var rel=links[i].getAttribute("rel");
+ var title=links[i].getAttribute("title");
+ if(rel.indexOf("style")!=-1&&title) {
+ links[i].disabled=true; // IE needs this to work. IE needs to die.
+ if(styletitle==title) { links[i].disabled=false; found=true; }
+ }
+ }
+}
+
+function get_active_stylesheet() {
+ var links=document.getElementsByTagName("link");
+ for(var i=0;i<links.length;i++) {
+ var rel=links[i].getAttribute("rel");
+ var title=links[i].getAttribute("title");
+ if(rel.indexOf("style")!=-1&&title&&!links[i].disabled) return title;
+ }
+ return null;
+}
+
+function check_news() {
+ var last_t = opcs.last;
+ var items = document.getElementsByClassName('ni');
+ var dates = document.getElementsByClassName('ni-d');
+ for(var i=0; i<items.length; i++) if(parseInt(items[i].dataset.t) > last_t) {
+ items[i].className += ' urgent';
+ dates[i].innerHTML = '<img src="/new.gif" style="width:18px;height:7px;"><br />' + dates[i].innerHTML;
+ }
+ opcs.last = Date.now() / 1000 | 0;
+ parse();
+}
+
+var lastTime = 0;
+var refreshInterval;
+var refreshMaxTime = 30;
+var refreshTime;
+var unread = {};
+var last_threads = 0;
+var last_serverTime = 0;
+var http_request = new XMLHttpRequest();
+
+function loadJSON() {
+ stopCounter("...");
+ var data_file = "/cgi/api/lastage?time=" + lastTime + "&limit=" + document.getElementById("limit").value;
+ http_request.open("GET", data_file, true);
+ http_request.send();
+}
+
+function setRead(threadId) {
+ if (threadId in unread) {
+ unread[threadId] = false;
+ updatePostList(last_threads, last_serverTime);
+ }
+}
+
+function updatePostList(threads, serverTime) {
+ if (refreshMaxTime <= 120) refreshMaxTime += 5;
+ var arrayLength = threads.length;
+ if (!arrayLength) return;
+
+ html = "";
+ last_threads = threads;
+ last_serverTime = serverTime;
+
+ var newposts = 0;
+ var newTitle = "Bienvenido a Internet BBS/IB";
+ var new_unread = false;
+ var news = [];
+
+ for (var i = 0; i < arrayLength; i++) {
+ thread = threads[i];
+ if (thread.bumped >= lastTime) {
+ unread[thread.id] = true;
+ news.push('- ' + thread.board_fulln + ': ' + thread.content);
+ new_unread = true;
+ }
+ if (unread[thread.id]) html += '<span class="new">';
+ html += '<a href="' + thread.url + '" class="thread" data-brd="' + thread.board_fulln + '" data-unix="' + thread.timestamp + '" data-last="' + thread.bumped + '" data-img="' + thread.thumb + '"><span class="brd">[' + thread.board_name + ']</span> <span class="cont">' + thread.content + '</span> <span class="rep">(' + thread.length + ')</span></a>';
+ if (unread[thread.id]) {
+ html += '</span>';
+ newposts++;
+ }
+ }
+ if (newposts) newTitle = '(' + newposts + ') ' + newTitle;
+ if (new_unread) {
+ document.getElementById("newposts").style = "color:red";
+ notif('Bienvenido a Internet BBS/IB', 'Hay nuevos mensajes:\n' + news.join('\n'));
+ refreshMaxTime = 10;
+ if (document.getElementById('autosound').checked) {
+ document.getElementById("machina").volume = 0.6;
+ document.getElementById("machina").play();
+ }
+ }
+ window.parent.document.title = newTitle;
+ document.title = newTitle;
+ document.getElementById("postlist").innerHTML = html;
+}
+
+function notif(title, msg) {
+ var n = new Notification(title, { body: msg });
+ setTimeout(n.close.bind(n), 10000);
+}
+
+function counter() {
+ if (refreshTime < 1) loadJSON();
+ else {
+ refreshTime--;
+ document.getElementById("counter").innerHTML = "– " + (refreshTime + 1);
+ }
+}
+
+function startCounter() {
+ refreshTime = refreshMaxTime;
+ counter();
+ refreshInterval = setInterval(counter, 1000);
+}
+
+function stopCounter(str) {
+ clearInterval(refreshInterval);
+ document.getElementById("counter").innerHTML = str;
+}
+
+function autoRefresh(e) {
+ if (chk.checked) {
+ if (chk_snd) chk_snd.disabled = false;
+ Notification.requestPermission();
+ lastTime = Math.floor(Date.now() / 1000);
+ refreshTime = refreshMaxTime;
+ startCounter();
+ } else {
+ if (chk_snd) chk_snd.disabled = true;
+ stopCounter("");
+ }
+}
+
+http_request.onreadystatechange = function() {
+ if (http_request.readyState == 4) {
+ var jsonObj = JSON.parse(http_request.responseText);
+ if (jsonObj.state == "success") {
+ updatePostList(jsonObj.threads, jsonObj.time);
+ lastTime = jsonObj.time;
+ if (chk.checked) startCounter();
+ }
+ }
+}
+
+function parse() { localStorage.setItem("home", JSON.stringify(opcs)); }
+
+document.addEventListener("DOMContentLoaded", function() {
+ if (localStorage.hasOwnProperty("home")) opcs=JSON.parse(localStorage.getItem("home"));
+ else { opcs={"style":"IB","auto":false,"sound":false,"last":0}; parse(); }
+ set_stylesheet(opcs.style);
+
+ var css = document.getElementById("change_style").getElementsByTagName("a");
+ for(var j=0;j<css.length;j++) {
+ css[j].addEventListener("click", function(e) { e.preventDefault(); set_stylesheet(this.textContent); });
+ }
+ document.getElementById("autorefresh").addEventListener("click", function(e) { opcs.auto=!opcs.auto; autoRefresh(); parse(); });
+ document.getElementById("autosound").addEventListener("click", function(e) { opcs.sound=!opcs.sound; parse(); });
+ check_news();
+
+ chk=document.getElementById("autorefresh");
+ chk_snd=document.getElementById("autosound");
+ if (opcs.auto) { chk.checked=true; autoRefresh(); } else chk.checked=false;
+ if (opcs.sound) chk_snd.checked=true; else chk_snd.checked=false;
+}); \ No newline at end of file
diff --git a/static/js/jquery.js b/static/js/jquery.js
new file mode 100644
index 0000000..4d8cc18
--- /dev/null
+++ b/static/js/jquery.js
@@ -0,0 +1,545 @@
+(function(window,undefined){var rootjQuery,readyList,core_strundefined=typeof undefined,location=window.location,document=window.document,docElem=document.documentElement,_jQuery=window.jQuery,_$=window.$,class2type={},core_deletedIds=[],core_version="2.0.2",core_concat=core_deletedIds.concat,core_push=core_deletedIds.push,core_slice=core_deletedIds.slice,core_indexOf=core_deletedIds.indexOf,core_toString=class2type.toString,core_hasOwn=class2type.hasOwnProperty,core_trim=core_version.trim,jQuery=function(selector,context){return new jQuery.fn.init(selector,context,rootjQuery);},core_pnum=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,core_rnotwhite=/\S+/g,rquickExpr=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,rsingleTag=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,rmsPrefix=/^-ms-/,rdashAlpha=/-([\da-z])/gi,fcamelCase=function(all,letter){return letter.toUpperCase();},completed=function(){document.removeEventListener("DOMContentLoaded",completed,false);window.removeEventListener("load",completed,false);jQuery.ready();};jQuery.fn=jQuery.prototype={jquery:core_version,constructor:jQuery,init:function(selector,context,rootjQuery){var match,elem;if(!selector){return this;}
+if(typeof selector==="string"){if(selector.charAt(0)==="<"&&selector.charAt(selector.length-1)===">"&&selector.length>=3){match=[null,selector,null];}else{match=rquickExpr.exec(selector);}
+if(match&&(match[1]||!context)){if(match[1]){context=context instanceof jQuery?context[0]:context;jQuery.merge(this,jQuery.parseHTML(match[1],context&&context.nodeType?context.ownerDocument||context:document,true));if(rsingleTag.test(match[1])&&jQuery.isPlainObject(context)){for(match in context){if(jQuery.isFunction(this[match])){this[match](context[match]);}else{this.attr(match,context[match]);}}}
+return this;}else{elem=document.getElementById(match[2]);if(elem&&elem.parentNode){this.length=1;this[0]=elem;}
+this.context=document;this.selector=selector;return this;}}else{if(!context||context.jquery){return(context||rootjQuery).find(selector);}else{return this.constructor(context).find(selector);}}}else{if(selector.nodeType){this.context=this[0]=selector;this.length=1;return this;}else{if(jQuery.isFunction(selector)){return rootjQuery.ready(selector);}}}
+if(selector.selector!==undefined){this.selector=selector.selector;this.context=selector.context;}
+return jQuery.makeArray(selector,this);},selector:"",length:0,toArray:function(){return core_slice.call(this);},get:function(num){return num==null?this.toArray():num<0?this[this.length+num]:this[num];},pushStack:function(elems){var ret=jQuery.merge(this.constructor(),elems);ret.prevObject=this;ret.context=this.context;return ret;},each:function(callback,args){return jQuery.each(this,callback,args);},ready:function(fn){jQuery.ready.promise().done(fn);return this;},slice:function(){return this.pushStack(core_slice.apply(this,arguments));},first:function(){return this.eq(0);},last:function(){return this.eq(-1);},eq:function(i){var len=this.length,j=+i+(i<0?len:0);return this.pushStack(j>=0&&j<len?[this[j]]:[]);},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem);}));},end:function(){return this.prevObject||this.constructor(null);},push:core_push,sort:[].sort,splice:[].splice};jQuery.fn.init.prototype=jQuery.fn;jQuery.extend=jQuery.fn.extend=function(){var options,name,src,copy,copyIsArray,clone,target=arguments[0]||{},i=1,length=arguments.length,deep=false;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2;}
+if(typeof target!=="object"&&!jQuery.isFunction(target)){target={};}
+if(length===i){target=this;--i;}
+for(;i<length;i++){if((options=arguments[i])!=null){for(name in options){src=target[name];copy=options[name];if(target===copy){continue;}
+if(deep&&copy&&(jQuery.isPlainObject(copy)||(copyIsArray=jQuery.isArray(copy)))){if(copyIsArray){copyIsArray=false;clone=src&&jQuery.isArray(src)?src:[];}else{clone=src&&jQuery.isPlainObject(src)?src:{};}
+target[name]=jQuery.extend(deep,clone,copy);}else{if(copy!==undefined){target[name]=copy;}}}}}
+return target;};jQuery.extend({expando:"jQuery"+(core_version+Math.random()).replace(/\D/g,""),noConflict:function(deep){if(window.$===jQuery){window.$=_$;}
+if(deep&&window.jQuery===jQuery){window.jQuery=_jQuery;}
+return jQuery;},isReady:false,readyWait:1,holdReady:function(hold){if(hold){jQuery.readyWait++;}else{jQuery.ready(true);}},ready:function(wait){if(wait===true?--jQuery.readyWait:jQuery.isReady){return;}
+jQuery.isReady=true;if(wait!==true&&--jQuery.readyWait>0){return;}
+readyList.resolveWith(document,[jQuery]);if(jQuery.fn.trigger){jQuery(document).trigger("ready").off("ready");}},isFunction:function(obj){return jQuery.type(obj)==="function";},isArray:Array.isArray,isWindow:function(obj){return obj!=null&&obj===obj.window;},isNumeric:function(obj){return!isNaN(parseFloat(obj))&&isFinite(obj);},type:function(obj){if(obj==null){return String(obj);}
+return typeof obj==="object"||typeof obj==="function"?class2type[core_toString.call(obj)]||"object":typeof obj;},isPlainObject:function(obj){if(jQuery.type(obj)!=="object"||obj.nodeType||jQuery.isWindow(obj)){return false;}
+try{if(obj.constructor&&!core_hasOwn.call(obj.constructor.prototype,"isPrototypeOf")){return false;}}catch(e){return false;}
+return true;},isEmptyObject:function(obj){var name;for(name in obj){return false;}
+return true;},error:function(msg){throw new Error(msg);},parseHTML:function(data,context,keepScripts){if(!data||typeof data!=="string"){return null;}
+if(typeof context==="boolean"){keepScripts=context;context=false;}
+context=context||document;var parsed=rsingleTag.exec(data),scripts=!keepScripts&&[];if(parsed){return[context.createElement(parsed[1])];}
+parsed=jQuery.buildFragment([data],context,scripts);if(scripts){jQuery(scripts).remove();}
+return jQuery.merge([],parsed.childNodes);},parseJSON:JSON.parse,parseXML:function(data){var xml,tmp;if(!data||typeof data!=="string"){return null;}
+try{tmp=new DOMParser;xml=tmp.parseFromString(data,"text/xml");}catch(e){xml=undefined;}
+if(!xml||xml.getElementsByTagName("parsererror").length){jQuery.error("Invalid XML: "+data);}
+return xml;},noop:function(){},globalEval:function(code){var script,indirect=eval;code=jQuery.trim(code);if(code){if(code.indexOf("use strict")===1){script=document.createElement("script");script.text=code;document.head.appendChild(script).parentNode.removeChild(script);}else{indirect(code);}}},camelCase:function(string){return string.replace(rmsPrefix,"ms-").replace(rdashAlpha,fcamelCase);},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toLowerCase()===name.toLowerCase();},each:function(obj,callback,args){var value,i=0,length=obj.length,isArray=isArraylike(obj);if(args){if(isArray){for(;i<length;i++){value=callback.apply(obj[i],args);if(value===false){break;}}}else{for(i in obj){value=callback.apply(obj[i],args);if(value===false){break;}}}}else{if(isArray){for(;i<length;i++){value=callback.call(obj[i],i,obj[i]);if(value===false){break;}}}else{for(i in obj){value=callback.call(obj[i],i,obj[i]);if(value===false){break;}}}}
+return obj;},trim:function(text){return text==null?"":core_trim.call(text);},makeArray:function(arr,results){var ret=results||[];if(arr!=null){if(isArraylike(Object(arr))){jQuery.merge(ret,typeof arr==="string"?[arr]:arr);}else{core_push.call(ret,arr);}}
+return ret;},inArray:function(elem,arr,i){return arr==null?-1:core_indexOf.call(arr,elem,i);},merge:function(first,second){var l=second.length,i=first.length,j=0;if(typeof l==="number"){for(;j<l;j++){first[i++]=second[j];}}else{while(second[j]!==undefined){first[i++]=second[j++];}}
+first.length=i;return first;},grep:function(elems,callback,inv){var retVal,ret=[],i=0,length=elems.length;inv=!!inv;for(;i<length;i++){retVal=!!callback(elems[i],i);if(inv!==retVal){ret.push(elems[i]);}}
+return ret;},map:function(elems,callback,arg){var value,i=0,length=elems.length,isArray=isArraylike(elems),ret=[];if(isArray){for(;i<length;i++){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value;}}}else{for(i in elems){value=callback(elems[i],i,arg);if(value!=null){ret[ret.length]=value;}}}
+return core_concat.apply([],ret);},guid:1,proxy:function(fn,context){var tmp,args,proxy;if(typeof context==="string"){tmp=fn[context];context=fn;fn=tmp;}
+if(!jQuery.isFunction(fn)){return undefined;}
+args=core_slice.call(arguments,2);proxy=function(){return fn.apply(context||this,args.concat(core_slice.call(arguments)));};proxy.guid=fn.guid=fn.guid||jQuery.guid++;return proxy;},access:function(elems,fn,key,value,chainable,emptyGet,raw){var i=0,length=elems.length,bulk=key==null;if(jQuery.type(key)==="object"){chainable=true;for(i in key){jQuery.access(elems,fn,i,key[i],true,emptyGet,raw);}}else{if(value!==undefined){chainable=true;if(!jQuery.isFunction(value)){raw=true;}
+if(bulk){if(raw){fn.call(elems,value);fn=null;}else{bulk=fn;fn=function(elem,key,value){return bulk.call(jQuery(elem),value);};}}
+if(fn){for(;i<length;i++){fn(elems[i],key,raw?value:value.call(elems[i],i,fn(elems[i],key)));}}}}
+return chainable?elems:bulk?fn.call(elems):length?fn(elems[0],key):emptyGet;},now:Date.now,swap:function(elem,options,callback,args){var ret,name,old={};for(name in options){old[name]=elem.style[name];elem.style[name]=options[name];}
+ret=callback.apply(elem,args||[]);for(name in options){elem.style[name]=old[name];}
+return ret;}});jQuery.ready.promise=function(obj){if(!readyList){readyList=jQuery.Deferred();if(document.readyState==="complete"){setTimeout(jQuery.ready);}else{document.addEventListener("DOMContentLoaded",completed,false);window.addEventListener("load",completed,false);}}
+return readyList.promise(obj);};jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(i,name){class2type["[object "+name+"]"]=name.toLowerCase();});function isArraylike(obj){var length=obj.length,type=jQuery.type(obj);if(jQuery.isWindow(obj)){return false;}
+if(obj.nodeType===1&&length){return true;}
+return type==="array"||type!=="function"&&(length===0||typeof length==="number"&&length>0&&length-1 in obj);}
+rootjQuery=jQuery(document);(function(window,undefined){var i,support,cachedruns,Expr,getText,isXML,compile,outermostContext,sortInput,setDocument,document,docElem,documentIsHTML,rbuggyQSA,rbuggyMatches,matches,contains,expando="sizzle"+ -new Date,preferredDoc=window.document,dirruns=0,done=0,classCache=createCache(),tokenCache=createCache(),compilerCache=createCache(),hasDuplicate=false,sortOrder=function(){return 0;},strundefined=typeof undefined,MAX_NEGATIVE=1<<31,hasOwn={}.hasOwnProperty,arr=[],pop=arr.pop,push_native=arr.push,push=arr.push,slice=arr.slice,indexOf=arr.indexOf||function(elem){var i=0,len=this.length;for(;i<len;i++){if(this[i]===elem){return i;}}
+return-1;},booleans="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",whitespace="[\\x20\\t\\r\\n\\f]",characterEncoding="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",identifier=characterEncoding.replace("w","w#"),attributes="\\["+whitespace+"*("+characterEncoding+")"+whitespace+"*(?:([*^$|!~]?=)"+whitespace+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+identifier+")|)|)"+whitespace+"*\\]",pseudos=":("+
+characterEncoding+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+attributes.replace(3,8)+")*)|.*)\\)|)",rtrim=new RegExp("^"+whitespace+"+|((?:^|[^\\\\])(?:\\\\.)*)"+whitespace+"+$","g"),rcomma=new RegExp("^"+whitespace+"*,"+whitespace+"*"),rcombinators=new RegExp("^"+whitespace+"*([>+~]|"+whitespace+")"+whitespace+"*"),rsibling=new RegExp(whitespace+"*[+~]"),rattributeQuotes=new RegExp("="+whitespace+"*([^\\]'\"]*)"+
+whitespace+"*\\]","g"),rpseudo=new RegExp(pseudos),ridentifier=new RegExp("^"+identifier+"$"),matchExpr={"ID":new RegExp("^#("+characterEncoding+")"),"CLASS":new RegExp("^\\.("+characterEncoding+")"),"TAG":new RegExp("^("+characterEncoding.replace("w","w*")+")"),"ATTR":new RegExp("^"+attributes),"PSEUDO":new RegExp("^"+pseudos),"CHILD":new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+whitespace+"*(even|odd|(([+-]|)(\\d*)n|)"+whitespace+"*(?:([+-]|)"+whitespace+"*(\\d+)|))"+whitespace+"*\\)|)","i"),"bool":new RegExp("^(?:"+booleans+")$","i"),"needsContext":new RegExp("^"+whitespace+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+whitespace+"*((?:-\\d)?\\d*)"+whitespace+"*\\)|)(?=[^-]|$)","i")},rnative=/^[^{]+\{\s*\[native \w/,rquickExpr=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,rinputs=/^(?:input|select|textarea|button)$/i,rheader=/^h\d$/i,rescape=/'|\\/g,runescape=new RegExp("\\\\([\\da-f]{1,6}"+
+whitespace+"?|("+whitespace+")|.)","ig"),funescape=function(_,escaped,escapedWhitespace){var high="0x"+escaped-65536;return high!==high||escapedWhitespace?escaped:high<0?String.fromCharCode(high+65536):String.fromCharCode(high>>10|55296,high&1023|56320);};try{push.apply(arr=slice.call(preferredDoc.childNodes),preferredDoc.childNodes);arr[preferredDoc.childNodes.length].nodeType;}catch(e){push={apply:arr.length?function(target,els){push_native.apply(target,slice.call(els));}:function(target,els){var j=target.length,i=0;while(target[j++]=els[i++]){}
+target.length=j-1;}};}
+function Sizzle(selector,context,results,seed){var match,elem,m,nodeType,i,groups,old,nid,newContext,newSelector;if((context?context.ownerDocument||context:preferredDoc)!==document){setDocument(context);}
+context=context||document;results=results||[];if(!selector||typeof selector!=="string"){return results;}
+if((nodeType=context.nodeType)!==1&&nodeType!==9){return[];}
+if(documentIsHTML&&!seed){if(match=rquickExpr.exec(selector)){if(m=match[1]){if(nodeType===9){elem=context.getElementById(m);if(elem&&elem.parentNode){if(elem.id===m){results.push(elem);return results;}}else{return results;}}else{if(context.ownerDocument&&(elem=context.ownerDocument.getElementById(m))&&contains(context,elem)&&elem.id===m){results.push(elem);return results;}}}else{if(match[2]){push.apply(results,context.getElementsByTagName(selector));return results;}else{if((m=match[3])&&support.getElementsByClassName&&context.getElementsByClassName){push.apply(results,context.getElementsByClassName(m));return results;}}}}
+if(support.qsa&&(!rbuggyQSA||!rbuggyQSA.test(selector))){nid=old=expando;newContext=context;newSelector=nodeType===9&&selector;if(nodeType===1&&context.nodeName.toLowerCase()!=="object"){groups=tokenize(selector);if(old=context.getAttribute("id")){nid=old.replace(rescape,"\\$&");}else{context.setAttribute("id",nid);}
+nid="[id='"+nid+"'] ";i=groups.length;while(i--){groups[i]=nid+toSelector(groups[i]);}
+newContext=rsibling.test(selector)&&context.parentNode||context;newSelector=groups.join(",");}
+if(newSelector){try{push.apply(results,newContext.querySelectorAll(newSelector));return results;}catch(qsaError){}finally{if(!old){context.removeAttribute("id");}}}}}
+return select(selector.replace(rtrim,"$1"),context,results,seed);}
+function isNative(fn){return rnative.test(fn+"");}
+function createCache(){var keys=[];function cache(key,value){if(keys.push(key+=" ")>Expr.cacheLength){delete cache[keys.shift()];}
+return cache[key]=value;}
+return cache;}
+function markFunction(fn){fn[expando]=true;return fn;}
+function assert(fn){var div=document.createElement("div");try{return!!fn(div);}catch(e$0){return false;}finally{if(div.parentNode){div.parentNode.removeChild(div);}
+div=null;}}
+function addHandle(attrs,handler,test){attrs=attrs.split("|");var current,i=attrs.length,setHandle=test?null:handler;while(i--){if(!(current=Expr.attrHandle[attrs[i]])||current===handler){Expr.attrHandle[attrs[i]]=setHandle;}}}
+function boolHandler(elem,name){var val=elem.getAttributeNode(name);return val&&val.specified?val.value:elem[name]===true?name.toLowerCase():null;}
+function interpolationHandler(elem,name){return elem.getAttribute(name,name.toLowerCase()==="type"?1:2);}
+function valueHandler(elem){if(elem.nodeName.toLowerCase()==="input"){return elem.defaultValue;}}
+function siblingCheck(a,b){var cur=b&&a,diff=cur&&a.nodeType===1&&b.nodeType===1&&(~b.sourceIndex||MAX_NEGATIVE)-(~a.sourceIndex||MAX_NEGATIVE);if(diff){return diff;}
+if(cur){while(cur=cur.nextSibling){if(cur===b){return-1;}}}
+return a?1:-1;}
+function createInputPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type===type;};}
+function createButtonPseudo(type){return function(elem){var name=elem.nodeName.toLowerCase();return(name==="input"||name==="button")&&elem.type===type;};}
+function createPositionalPseudo(fn){return markFunction(function(argument){argument=+argument;return markFunction(function(seed,matches){var j,matchIndexes=fn([],seed.length,argument),i=matchIndexes.length;while(i--){if(seed[j=matchIndexes[i]]){seed[j]=!(matches[j]=seed[j]);}}});});}
+isXML=Sizzle.isXML=function(elem){var documentElement=elem&&(elem.ownerDocument||elem).documentElement;return documentElement?documentElement.nodeName!=="HTML":false;};support=Sizzle.support={};setDocument=Sizzle.setDocument=function(node){var doc=node?node.ownerDocument||node:preferredDoc,parent=doc.parentWindow;if(doc===document||doc.nodeType!==9||!doc.documentElement){return document;}
+document=doc;docElem=doc.documentElement;documentIsHTML=!isXML(doc);if(parent&&parent.frameElement){parent.attachEvent("onbeforeunload",function(){setDocument();});}
+support.attributes=assert(function(div){div.innerHTML="<a href='#'></a>";addHandle("type|href|height|width",interpolationHandler,div.firstChild.getAttribute("href")==="#");addHandle(booleans,boolHandler,div.getAttribute("disabled")==null);div.className="i";return!div.getAttribute("className");});support.input=assert(function(div){div.innerHTML="<input>";div.firstChild.setAttribute("value","");return div.firstChild.getAttribute("value")==="";});addHandle("value",valueHandler,support.attributes&&support.input);support.getElementsByTagName=assert(function(div){div.appendChild(doc.createComment(""));return!div.getElementsByTagName("*").length;});support.getElementsByClassName=assert(function(div){div.innerHTML="<div class='a'></div><div class='a i'></div>";div.firstChild.className="i";return div.getElementsByClassName("i").length===2;});support.getById=assert(function(div){docElem.appendChild(div).id=expando;return!doc.getElementsByName||!doc.getElementsByName(expando).length;});if(support.getById){Expr.find["ID"]=function(id,context){if(typeof context.getElementById!==strundefined&&documentIsHTML){var m=context.getElementById(id);return m&&m.parentNode?[m]:[];}};Expr.filter["ID"]=function(id){var attrId=id.replace(runescape,funescape);return function(elem){return elem.getAttribute("id")===attrId;};};}else{delete Expr.find["ID"];Expr.filter["ID"]=function(id){var attrId=id.replace(runescape,funescape);return function(elem){var node=typeof elem.getAttributeNode!==strundefined&&elem.getAttributeNode("id");return node&&node.value===attrId;};};}
+Expr.find["TAG"]=support.getElementsByTagName?function(tag,context){if(typeof context.getElementsByTagName!==strundefined){return context.getElementsByTagName(tag);}}:function(tag,context){var elem,tmp=[],i=0,results=context.getElementsByTagName(tag);if(tag==="*"){while(elem=results[i++]){if(elem.nodeType===1){tmp.push(elem);}}
+return tmp;}
+return results;};Expr.find["CLASS"]=support.getElementsByClassName&&function(className,context){if(typeof context.getElementsByClassName!==strundefined&&documentIsHTML){return context.getElementsByClassName(className);}};rbuggyMatches=[];rbuggyQSA=[];if(support.qsa=isNative(doc.querySelectorAll)){assert(function(div){div.innerHTML="<select><option selected=''></option></select>";if(!div.querySelectorAll("[selected]").length){rbuggyQSA.push("\\["+whitespace+"*(?:value|"+booleans+")");}
+if(!div.querySelectorAll(":checked").length){rbuggyQSA.push(":checked");}});assert(function(div){var input=doc.createElement("input");input.setAttribute("type","hidden");div.appendChild(input).setAttribute("t","");if(div.querySelectorAll("[t^='']").length){rbuggyQSA.push("[*^$]="+whitespace+"*(?:''|\"\")");}
+if(!div.querySelectorAll(":enabled").length){rbuggyQSA.push(":enabled",":disabled");}
+div.querySelectorAll("*,:x");rbuggyQSA.push(",.*:");});}
+if(support.matchesSelector=isNative(matches=docElem.webkitMatchesSelector||docElem.mozMatchesSelector||docElem.oMatchesSelector||docElem.msMatchesSelector)){assert(function(div){support.disconnectedMatch=matches.call(div,"div");matches.call(div,"[s!='']:x");rbuggyMatches.push("!=",pseudos);});}
+rbuggyQSA=rbuggyQSA.length&&new RegExp(rbuggyQSA.join("|"));rbuggyMatches=rbuggyMatches.length&&new RegExp(rbuggyMatches.join("|"));contains=isNative(docElem.contains)||docElem.compareDocumentPosition?function(a,b){var adown=a.nodeType===9?a.documentElement:a,bup=b&&b.parentNode;return a===bup||!!(bup&&bup.nodeType===1&&(adown.contains?adown.contains(bup):a.compareDocumentPosition&&a.compareDocumentPosition(bup)&16));}:function(a,b){if(b){while(b=b.parentNode){if(b===a){return true;}}}
+return false;};support.sortDetached=assert(function(div1){return div1.compareDocumentPosition(doc.createElement("div"))&1;});sortOrder=docElem.compareDocumentPosition?function(a,b){if(a===b){hasDuplicate=true;return 0;}
+var compare=b.compareDocumentPosition&&a.compareDocumentPosition&&a.compareDocumentPosition(b);if(compare){if(compare&1||!support.sortDetached&&b.compareDocumentPosition(a)===compare){if(a===doc||contains(preferredDoc,a)){return-1;}
+if(b===doc||contains(preferredDoc,b)){return 1;}
+return sortInput?indexOf.call(sortInput,a)-indexOf.call(sortInput,b):0;}
+return compare&4?-1:1;}
+return a.compareDocumentPosition?-1:1;}:function(a,b){var cur,i=0,aup=a.parentNode,bup=b.parentNode,ap=[a],bp=[b];if(a===b){hasDuplicate=true;return 0;}else{if(!aup||!bup){return a===doc?-1:b===doc?1:aup?-1:bup?1:sortInput?indexOf.call(sortInput,a)-indexOf.call(sortInput,b):0;}else{if(aup===bup){return siblingCheck(a,b);}}}
+cur=a;while(cur=cur.parentNode){ap.unshift(cur);}
+cur=b;while(cur=cur.parentNode){bp.unshift(cur);}
+while(ap[i]===bp[i]){i++;}
+return i?siblingCheck(ap[i],bp[i]):ap[i]===preferredDoc?-1:bp[i]===preferredDoc?1:0;};return doc;};Sizzle.matches=function(expr,elements){return Sizzle(expr,null,null,elements);};Sizzle.matchesSelector=function(elem,expr){if((elem.ownerDocument||elem)!==document){setDocument(elem);}
+expr=expr.replace(rattributeQuotes,"='$1']");if(support.matchesSelector&&documentIsHTML&&(!rbuggyMatches||!rbuggyMatches.test(expr))&&(!rbuggyQSA||!rbuggyQSA.test(expr))){try{var ret=matches.call(elem,expr);if(ret||support.disconnectedMatch||elem.document&&elem.document.nodeType!==11){return ret;}}catch(e$1){}}
+return Sizzle(expr,document,null,[elem]).length>0;};Sizzle.contains=function(context,elem){if((context.ownerDocument||context)!==document){setDocument(context);}
+return contains(context,elem);};Sizzle.attr=function(elem,name){if((elem.ownerDocument||elem)!==document){setDocument(elem);}
+var fn=Expr.attrHandle[name.toLowerCase()],val=fn&&hasOwn.call(Expr.attrHandle,name.toLowerCase())?fn(elem,name,!documentIsHTML):undefined;return val===undefined?support.attributes||!documentIsHTML?elem.getAttribute(name):(val=elem.getAttributeNode(name))&&val.specified?val.value:null:val;};Sizzle.error=function(msg){throw new Error("Syntax error, unrecognized expression: "+msg);};Sizzle.uniqueSort=function(results){var elem,duplicates=[],j=0,i=0;hasDuplicate=!support.detectDuplicates;sortInput=!support.sortStable&&results.slice(0);results.sort(sortOrder);if(hasDuplicate){while(elem=results[i++]){if(elem===results[i]){j=duplicates.push(i);}}
+while(j--){results.splice(duplicates[j],1);}}
+return results;};getText=Sizzle.getText=function(elem){var node,ret="",i=0,nodeType=elem.nodeType;if(!nodeType){for(;node=elem[i];i++){ret+=getText(node);}}else{if(nodeType===1||nodeType===9||nodeType===11){if(typeof elem.textContent==="string"){return elem.textContent;}else{for(elem=elem.firstChild;elem;elem=elem.nextSibling){ret+=getText(elem);}}}else{if(nodeType===3||nodeType===4){return elem.nodeValue;}}}
+return ret;};Expr=Sizzle.selectors={cacheLength:50,createPseudo:markFunction,match:matchExpr,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:true}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:true},"~":{dir:"previousSibling"}},preFilter:{"ATTR":function(match){match[1]=match[1].replace(runescape,funescape);match[3]=(match[4]||match[5]||"").replace(runescape,funescape);if(match[2]==="~="){match[3]=" "+match[3]+" ";}
+return match.slice(0,4);},"CHILD":function(match){match[1]=match[1].toLowerCase();if(match[1].slice(0,3)==="nth"){if(!match[3]){Sizzle.error(match[0]);}
+match[4]=+(match[4]?match[5]+(match[6]||1):2*(match[3]==="even"||match[3]==="odd"));match[5]=+(match[7]+match[8]||match[3]==="odd");}else{if(match[3]){Sizzle.error(match[0]);}}
+return match;},"PSEUDO":function(match){var excess,unquoted=!match[5]&&match[2];if(matchExpr["CHILD"].test(match[0])){return null;}
+if(match[3]&&match[4]!==undefined){match[2]=match[4];}else{if(unquoted&&rpseudo.test(unquoted)&&(excess=tokenize(unquoted,true))&&(excess=unquoted.indexOf(")",unquoted.length-excess)-unquoted.length)){match[0]=match[0].slice(0,excess);match[2]=unquoted.slice(0,excess);}}
+return match.slice(0,3);}},filter:{"TAG":function(nodeNameSelector){var nodeName=nodeNameSelector.replace(runescape,funescape).toLowerCase();return nodeNameSelector==="*"?function(){return true;}:function(elem){return elem.nodeName&&elem.nodeName.toLowerCase()===nodeName;};},"CLASS":function(className){var pattern=classCache[className+" "];return pattern||(pattern=new RegExp("(^|"+whitespace+")"+className+"("+whitespace+"|$)"))&&classCache(className,function(elem){return pattern.test(typeof elem.className==="string"&&elem.className||typeof elem.getAttribute!==strundefined&&elem.getAttribute("class")||"");});},"ATTR":function(name,operator,check){return function(elem){var result=Sizzle.attr(elem,name);if(result==null){return operator==="!=";}
+if(!operator){return true;}
+result+="";return operator==="="?result===check:operator==="!="?result!==check:operator==="^="?check&&result.indexOf(check)===0:operator==="*="?check&&result.indexOf(check)>-1:operator==="$="?check&&result.slice(-check.length)===check:operator==="~="?(" "+result+" ").indexOf(check)>-1:operator==="|="?result===check||result.slice(0,check.length+1)===check+"-":false;};},"CHILD":function(type,what,argument,first,last){var simple=type.slice(0,3)!=="nth",forward=type.slice(-4)!=="last",ofType=what==="of-type";return first===1&&last===0?function(elem){return!!elem.parentNode;}:function(elem,context,xml){var cache,outerCache,node,diff,nodeIndex,start,dir=simple!==forward?"nextSibling":"previousSibling",parent=elem.parentNode,name=ofType&&elem.nodeName.toLowerCase(),useCache=!xml&&!ofType;if(parent){if(simple){while(dir){node=elem;while(node=node[dir]){if(ofType?node.nodeName.toLowerCase()===name:node.nodeType===1){return false;}}
+start=dir=type==="only"&&!start&&"nextSibling";}
+return true;}
+start=[forward?parent.firstChild:parent.lastChild];if(forward&&useCache){outerCache=parent[expando]||(parent[expando]={});cache=outerCache[type]||[];nodeIndex=cache[0]===dirruns&&cache[1];diff=cache[0]===dirruns&&cache[2];node=nodeIndex&&parent.childNodes[nodeIndex];while(node=++nodeIndex&&node&&node[dir]||(diff=nodeIndex=0)||start.pop()){if(node.nodeType===1&&++diff&&node===elem){outerCache[type]=[dirruns,nodeIndex,diff];break;}}}else{if(useCache&&(cache=(elem[expando]||(elem[expando]={}))[type])&&cache[0]===dirruns){diff=cache[1];}else{while(node=++nodeIndex&&node&&node[dir]||(diff=nodeIndex=0)||start.pop()){if((ofType?node.nodeName.toLowerCase()===name:node.nodeType===1)&&++diff){if(useCache){(node[expando]||(node[expando]={}))[type]=[dirruns,diff];}
+if(node===elem){break;}}}}}
+diff-=last;return diff===first||diff%first===0&&diff / first>=0;}};},"PSEUDO":function(pseudo,argument){var args,fn=Expr.pseudos[pseudo]||Expr.setFilters[pseudo.toLowerCase()]||Sizzle.error("unsupported pseudo: "+pseudo);if(fn[expando]){return fn(argument);}
+if(fn.length>1){args=[pseudo,pseudo,"",argument];return Expr.setFilters.hasOwnProperty(pseudo.toLowerCase())?markFunction(function(seed,matches){var idx,matched=fn(seed,argument),i=matched.length;while(i--){idx=indexOf.call(seed,matched[i]);seed[idx]=!(matches[idx]=matched[i]);}}):function(elem){return fn(elem,0,args);};}
+return fn;}},pseudos:{"not":markFunction(function(selector){var input=[],results=[],matcher=compile(selector.replace(rtrim,"$1"));return matcher[expando]?markFunction(function(seed,matches,context,xml){var elem,unmatched=matcher(seed,null,xml,[]),i=seed.length;while(i--){if(elem=unmatched[i]){seed[i]=!(matches[i]=elem);}}}):function(elem,context,xml){input[0]=elem;matcher(input,null,xml,results);return!results.pop();};}),"has":markFunction(function(selector){return function(elem){return Sizzle(selector,elem).length>0;};}),"contains":markFunction(function(text){return function(elem){return(elem.textContent||elem.innerText||getText(elem)).indexOf(text)>-1;};}),"lang":markFunction(function(lang){if(!ridentifier.test(lang||"")){Sizzle.error("unsupported lang: "+lang);}
+lang=lang.replace(runescape,funescape).toLowerCase();return function(elem){var elemLang;do{if(elemLang=documentIsHTML?elem.lang:elem.getAttribute("xml:lang")||elem.getAttribute("lang")){elemLang=elemLang.toLowerCase();return elemLang===lang||elemLang.indexOf(lang+"-")===0;}}while((elem=elem.parentNode)&&elem.nodeType===1);return false;};}),"target":function(elem){var hash=window.location&&window.location.hash;return hash&&hash.slice(1)===elem.id;},"root":function(elem){return elem===docElem;},"focus":function(elem){return elem===document.activeElement&&(!document.hasFocus||document.hasFocus())&&!!(elem.type||elem.href||~elem.tabIndex);},"enabled":function(elem){return elem.disabled===false;},"disabled":function(elem){return elem.disabled===true;},"checked":function(elem){var nodeName=elem.nodeName.toLowerCase();return nodeName==="input"&&!!elem.checked||nodeName==="option"&&!!elem.selected;},"selected":function(elem){if(elem.parentNode){elem.parentNode.selectedIndex;}
+return elem.selected===true;},"empty":function(elem){for(elem=elem.firstChild;elem;elem=elem.nextSibling){if(elem.nodeName>"@"||elem.nodeType===3||elem.nodeType===4){return false;}}
+return true;},"parent":function(elem){return!Expr.pseudos["empty"](elem);},"header":function(elem){return rheader.test(elem.nodeName);},"input":function(elem){return rinputs.test(elem.nodeName);},"button":function(elem){var name=elem.nodeName.toLowerCase();return name==="input"&&elem.type==="button"||name==="button";},"text":function(elem){var attr;return elem.nodeName.toLowerCase()==="input"&&elem.type==="text"&&((attr=elem.getAttribute("type"))==null||attr.toLowerCase()===elem.type);},"first":createPositionalPseudo(function(){return[0];}),"last":createPositionalPseudo(function(matchIndexes,length){return[length-1];}),"eq":createPositionalPseudo(function(matchIndexes,length,argument){return[argument<0?argument+length:argument];}),"even":createPositionalPseudo(function(matchIndexes,length){var i=0;for(;i<length;i+=2){matchIndexes.push(i);}
+return matchIndexes;}),"odd":createPositionalPseudo(function(matchIndexes,length){var i=1;for(;i<length;i+=2){matchIndexes.push(i);}
+return matchIndexes;}),"lt":createPositionalPseudo(function(matchIndexes,length,argument){var i=argument<0?argument+length:argument;for(;--i>=0;){matchIndexes.push(i);}
+return matchIndexes;}),"gt":createPositionalPseudo(function(matchIndexes,length,argument){var i=argument<0?argument+length:argument;for(;++i<length;){matchIndexes.push(i);}
+return matchIndexes;})}};for(i in{radio:true,checkbox:true,file:true,password:true,image:true}){Expr.pseudos[i]=createInputPseudo(i);}
+for(i in{submit:true,reset:true}){Expr.pseudos[i]=createButtonPseudo(i);}
+function tokenize(selector,parseOnly){var matched,match,tokens,type,soFar,groups,preFilters,cached=tokenCache[selector+" "];if(cached){return parseOnly?0:cached.slice(0);}
+soFar=selector;groups=[];preFilters=Expr.preFilter;while(soFar){if(!matched||(match=rcomma.exec(soFar))){if(match){soFar=soFar.slice(match[0].length)||soFar;}
+groups.push(tokens=[]);}
+matched=false;if(match=rcombinators.exec(soFar)){matched=match.shift();tokens.push({value:matched,type:match[0].replace(rtrim," ")});soFar=soFar.slice(matched.length);}
+for(type in Expr.filter){if((match=matchExpr[type].exec(soFar))&&(!preFilters[type]||(match=preFilters[type](match)))){matched=match.shift();tokens.push({value:matched,type:type,matches:match});soFar=soFar.slice(matched.length);}}
+if(!matched){break;}}
+return parseOnly?soFar.length:soFar?Sizzle.error(selector):tokenCache(selector,groups).slice(0);}
+function toSelector(tokens){var i=0,len=tokens.length,selector="";for(;i<len;i++){selector+=tokens[i].value;}
+return selector;}
+function addCombinator(matcher,combinator,base){var dir=combinator.dir,checkNonElements=base&&dir==="parentNode",doneName=done++;return combinator.first?function(elem,context,xml){while(elem=elem[dir]){if(elem.nodeType===1||checkNonElements){return matcher(elem,context,xml);}}}:function(elem,context,xml){var data,cache,outerCache,dirkey=dirruns+" "+doneName;if(xml){while(elem=elem[dir]){if(elem.nodeType===1||checkNonElements){if(matcher(elem,context,xml)){return true;}}}}else{while(elem=elem[dir]){if(elem.nodeType===1||checkNonElements){outerCache=elem[expando]||(elem[expando]={});if((cache=outerCache[dir])&&cache[0]===dirkey){if((data=cache[1])===true||data===cachedruns){return data===true;}}else{cache=outerCache[dir]=[dirkey];cache[1]=matcher(elem,context,xml)||cachedruns;if(cache[1]===true){return true;}}}}}};}
+function elementMatcher(matchers){return matchers.length>1?function(elem,context,xml){var i=matchers.length;while(i--){if(!matchers[i](elem,context,xml)){return false;}}
+return true;}:matchers[0];}
+function condense(unmatched,map,filter,context,xml){var elem,newUnmatched=[],i=0,len=unmatched.length,mapped=map!=null;for(;i<len;i++){if(elem=unmatched[i]){if(!filter||filter(elem,context,xml)){newUnmatched.push(elem);if(mapped){map.push(i);}}}}
+return newUnmatched;}
+function setMatcher(preFilter,selector,matcher,postFilter,postFinder,postSelector){if(postFilter&&!postFilter[expando]){postFilter=setMatcher(postFilter);}
+if(postFinder&&!postFinder[expando]){postFinder=setMatcher(postFinder,postSelector);}
+return markFunction(function(seed,results,context,xml){var temp,i,elem,preMap=[],postMap=[],preexisting=results.length,elems=seed||multipleContexts(selector||"*",context.nodeType?[context]:context,[]),matcherIn=preFilter&&(seed||!selector)?condense(elems,preMap,preFilter,context,xml):elems,matcherOut=matcher?postFinder||(seed?preFilter:preexisting||postFilter)?[]:results:matcherIn;if(matcher){matcher(matcherIn,matcherOut,context,xml);}
+if(postFilter){temp=condense(matcherOut,postMap);postFilter(temp,[],context,xml);i=temp.length;while(i--){if(elem=temp[i]){matcherOut[postMap[i]]=!(matcherIn[postMap[i]]=elem);}}}
+if(seed){if(postFinder||preFilter){if(postFinder){temp=[];i=matcherOut.length;while(i--){if(elem=matcherOut[i]){temp.push(matcherIn[i]=elem);}}
+postFinder(null,matcherOut=[],temp,xml);}
+i=matcherOut.length;while(i--){if((elem=matcherOut[i])&&(temp=postFinder?indexOf.call(seed,elem):preMap[i])>-1){seed[temp]=!(results[temp]=elem);}}}}else{matcherOut=condense(matcherOut===results?matcherOut.splice(preexisting,matcherOut.length):matcherOut);if(postFinder){postFinder(null,results,matcherOut,xml);}else{push.apply(results,matcherOut);}}});}
+function matcherFromTokens(tokens){var checkContext,matcher,j,len=tokens.length,leadingRelative=Expr.relative[tokens[0].type],implicitRelative=leadingRelative||Expr.relative[" "],i=leadingRelative?1:0,matchContext=addCombinator(function(elem){return elem===checkContext;},implicitRelative,true),matchAnyContext=addCombinator(function(elem){return indexOf.call(checkContext,elem)>-1;},implicitRelative,true),matchers=[function(elem,context,xml){return!leadingRelative&&(xml||context!==outermostContext)||((checkContext=context).nodeType?matchContext(elem,context,xml):matchAnyContext(elem,context,xml));}];for(;i<len;i++){if(matcher=Expr.relative[tokens[i].type]){matchers=[addCombinator(elementMatcher(matchers),matcher)];}else{matcher=Expr.filter[tokens[i].type].apply(null,tokens[i].matches);if(matcher[expando]){j=++i;for(;j<len;j++){if(Expr.relative[tokens[j].type]){break;}}
+return setMatcher(i>1&&elementMatcher(matchers),i>1&&toSelector(tokens.slice(0,i-1).concat({value:tokens[i-2].type===" "?"*":""})).replace(rtrim,"$1"),matcher,i<j&&matcherFromTokens(tokens.slice(i,j)),j<len&&matcherFromTokens(tokens=tokens.slice(j)),j<len&&toSelector(tokens));}
+matchers.push(matcher);}}
+return elementMatcher(matchers);}
+function matcherFromGroupMatchers(elementMatchers,setMatchers){var matcherCachedRuns=0,bySet=setMatchers.length>0,byElement=elementMatchers.length>0,superMatcher=function(seed,context,xml,results,expandContext){var elem,j,matcher,setMatched=[],matchedCount=0,i="0",unmatched=seed&&[],outermost=expandContext!=null,contextBackup=outermostContext,elems=seed||byElement&&Expr.find["TAG"]("*",expandContext&&context.parentNode||context),dirrunsUnique=dirruns+=contextBackup==null?1:Math.random()||.1;if(outermost){outermostContext=context!==document&&context;cachedruns=matcherCachedRuns;}
+for(;(elem=elems[i])!=null;i++){if(byElement&&elem){j=0;while(matcher=elementMatchers[j++]){if(matcher(elem,context,xml)){results.push(elem);break;}}
+if(outermost){dirruns=dirrunsUnique;cachedruns=++matcherCachedRuns;}}
+if(bySet){if(elem=!matcher&&elem){matchedCount--;}
+if(seed){unmatched.push(elem);}}}
+matchedCount+=i;if(bySet&&i!==matchedCount){j=0;while(matcher=setMatchers[j++]){matcher(unmatched,setMatched,context,xml);}
+if(seed){if(matchedCount>0){while(i--){if(!(unmatched[i]||setMatched[i])){setMatched[i]=pop.call(results);}}}
+setMatched=condense(setMatched);}
+push.apply(results,setMatched);if(outermost&&!seed&&setMatched.length>0&&matchedCount+setMatchers.length>1){Sizzle.uniqueSort(results);}}
+if(outermost){dirruns=dirrunsUnique;outermostContext=contextBackup;}
+return unmatched;};return bySet?markFunction(superMatcher):superMatcher;}
+compile=Sizzle.compile=function(selector,group){var i,setMatchers=[],elementMatchers=[],cached=compilerCache[selector+" "];if(!cached){if(!group){group=tokenize(selector);}
+i=group.length;while(i--){cached=matcherFromTokens(group[i]);if(cached[expando]){setMatchers.push(cached);}else{elementMatchers.push(cached);}}
+cached=compilerCache(selector,matcherFromGroupMatchers(elementMatchers,setMatchers));}
+return cached;};function multipleContexts(selector,contexts,results){var i=0,len=contexts.length;for(;i<len;i++){Sizzle(selector,contexts[i],results);}
+return results;}
+function select(selector,context,results,seed){var i,tokens,token,type,find,match=tokenize(selector);if(!seed){if(match.length===1){tokens=match[0]=match[0].slice(0);if(tokens.length>2&&(token=tokens[0]).type==="ID"&&support.getById&&context.nodeType===9&&documentIsHTML&&Expr.relative[tokens[1].type]){context=(Expr.find["ID"](token.matches[0].replace(runescape,funescape),context)||[])[0];if(!context){return results;}
+selector=selector.slice(tokens.shift().value.length);}
+i=matchExpr["needsContext"].test(selector)?0:tokens.length;while(i--){token=tokens[i];if(Expr.relative[type=token.type]){break;}
+if(find=Expr.find[type]){if(seed=find(token.matches[0].replace(runescape,funescape),rsibling.test(tokens[0].type)&&context.parentNode||context)){tokens.splice(i,1);selector=seed.length&&toSelector(tokens);if(!selector){push.apply(results,seed);return results;}
+break;}}}}}
+compile(selector,match)(seed,context,!documentIsHTML,results,rsibling.test(selector));return results;}
+Expr.pseudos["nth"]=Expr.pseudos["eq"];function setFilters(){}
+setFilters.prototype=Expr.filters=Expr.pseudos;Expr.setFilters=new setFilters;support.sortStable=expando.split("").sort(sortOrder).join("")===expando;setDocument();[0,0].sort(sortOrder);support.detectDuplicates=hasDuplicate;jQuery.find=Sizzle;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.pseudos;jQuery.unique=Sizzle.uniqueSort;jQuery.text=Sizzle.getText;jQuery.isXMLDoc=Sizzle.isXML;jQuery.contains=Sizzle.contains;})(window);var optionsCache={};function createOptions(options){var object=optionsCache[options]={};jQuery.each(options.match(core_rnotwhite)||[],function(_,flag){object[flag]=true;});return object;}
+jQuery.Callbacks=function(options){options=typeof options==="string"?optionsCache[options]||createOptions(options):jQuery.extend({},options);var memory,fired,firing,firingStart,firingLength,firingIndex,list=[],stack=!options.once&&[],fire=function(data){memory=options.memory&&data;fired=true;firingIndex=firingStart||0;firingStart=0;firingLength=list.length;firing=true;for(;list&&firingIndex<firingLength;firingIndex++){if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse){memory=false;break;}}
+firing=false;if(list){if(stack){if(stack.length){fire(stack.shift());}}else{if(memory){list=[];}else{self.disable();}}}},self={add:function(){if(list){var start=list.length;(function add(args){jQuery.each(args,function(_,arg){var type=jQuery.type(arg);if(type==="function"){if(!options.unique||!self.has(arg)){list.push(arg);}}else{if(arg&&arg.length&&type!=="string"){add(arg);}}});})(arguments);if(firing){firingLength=list.length;}else{if(memory){firingStart=start;fire(memory);}}}
+return this;},remove:function(){if(list){jQuery.each(arguments,function(_,arg){var index;while((index=jQuery.inArray(arg,list,index))>-1){list.splice(index,1);if(firing){if(index<=firingLength){firingLength--;}
+if(index<=firingIndex){firingIndex--;}}}});}
+return this;},has:function(fn){return fn?jQuery.inArray(fn,list)>-1:!!(list&&list.length);},empty:function(){list=[];firingLength=0;return this;},disable:function(){list=stack=memory=undefined;return this;},disabled:function(){return!list;},lock:function(){stack=undefined;if(!memory){self.disable();}
+return this;},locked:function(){return!stack;},fireWith:function(context,args){args=args||[];args=[context,args.slice?args.slice():args];if(list&&(!fired||stack)){if(firing){stack.push(args);}else{fire(args);}}
+return this;},fire:function(){self.fireWith(this,arguments);return this;},fired:function(){return!!fired;}};return self;};jQuery.extend({Deferred:function(func){var tuples=[["resolve","done",jQuery.Callbacks("once memory"),"resolved"],["reject","fail",jQuery.Callbacks("once memory"),"rejected"],["notify","progress",jQuery.Callbacks("memory")]],state="pending",promise={state:function(){return state;},always:function(){deferred.done(arguments).fail(arguments);return this;},then:function(){var fns=arguments;return jQuery.Deferred(function(newDefer){jQuery.each(tuples,function(i,tuple){var action=tuple[0],fn=jQuery.isFunction(fns[i])&&fns[i];deferred[tuple[1]](function(){var returned=fn&&fn.apply(this,arguments);if(returned&&jQuery.isFunction(returned.promise)){returned.promise().done(newDefer.resolve).fail(newDefer.reject).progress(newDefer.notify);}else{newDefer[action+"With"](this===promise?newDefer.promise():this,fn?[returned]:arguments);}});});fns=null;}).promise();},promise:function(obj){return obj!=null?jQuery.extend(obj,promise):promise;}},deferred={};promise.pipe=promise.then;jQuery.each(tuples,function(i,tuple){var list=tuple[2],stateString=tuple[3];promise[tuple[1]]=list.add;if(stateString){list.add(function(){state=stateString;},tuples[i^1][2].disable,tuples[2][2].lock);}
+deferred[tuple[0]]=function(){deferred[tuple[0]+"With"](this===deferred?promise:this,arguments);return this;};deferred[tuple[0]+"With"]=list.fireWith;});promise.promise(deferred);if(func){func.call(deferred,deferred);}
+return deferred;},when:function(subordinate){var i=0,resolveValues=core_slice.call(arguments),length=resolveValues.length,remaining=length!==1||subordinate&&jQuery.isFunction(subordinate.promise)?length:0,deferred=remaining===1?subordinate:jQuery.Deferred(),updateFunc=function(i,contexts,values){return function(value){contexts[i]=this;values[i]=arguments.length>1?core_slice.call(arguments):value;if(values===progressValues){deferred.notifyWith(contexts,values);}else{if(!--remaining){deferred.resolveWith(contexts,values);}}};},progressValues,progressContexts,resolveContexts;if(length>1){progressValues=new Array(length);progressContexts=new Array(length);resolveContexts=new Array(length);for(;i<length;i++){if(resolveValues[i]&&jQuery.isFunction(resolveValues[i].promise)){resolveValues[i].promise().done(updateFunc(i,resolveContexts,resolveValues)).fail(deferred.reject).progress(updateFunc(i,progressContexts,progressValues));}else{--remaining;}}}
+if(!remaining){deferred.resolveWith(resolveContexts,resolveValues);}
+return deferred.promise();}});jQuery.support=function(support){var input=document.createElement("input"),fragment=document.createDocumentFragment(),div=document.createElement("div"),select=document.createElement("select"),opt=select.appendChild(document.createElement("option"));if(!input.type){return support;}
+input.type="checkbox";support.checkOn=input.value!=="";support.optSelected=opt.selected;support.reliableMarginRight=true;support.boxSizingReliable=true;support.pixelPosition=false;input.checked=true;support.noCloneChecked=input.cloneNode(true).checked;select.disabled=true;support.optDisabled=!opt.disabled;input=document.createElement("input");input.value="t";input.type="radio";support.radioValue=input.value==="t";input.setAttribute("checked","t");input.setAttribute("name","t");fragment.appendChild(input);support.checkClone=fragment.cloneNode(true).cloneNode(true).lastChild.checked;support.focusinBubbles="onfocusin"in window;div.style.backgroundClip="content-box";div.cloneNode(true).style.backgroundClip="";support.clearCloneStyle=div.style.backgroundClip==="content-box";jQuery(function(){var container,marginDiv,divReset="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",body=document.getElementsByTagName("body")[0];if(!body){return;}
+container=document.createElement("div");container.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";body.appendChild(container).appendChild(div);div.innerHTML="";div.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%";jQuery.swap(body,body.style.zoom!=null?{zoom:1}:{},function(){support.boxSizing=div.offsetWidth===4;});if(window.getComputedStyle){support.pixelPosition=(window.getComputedStyle(div,null)||{}).top!=="1%";support.boxSizingReliable=(window.getComputedStyle(div,null)||{width:"4px"}).width==="4px";marginDiv=div.appendChild(document.createElement("div"));marginDiv.style.cssText=div.style.cssText=divReset;marginDiv.style.marginRight=marginDiv.style.width="0";div.style.width="1px";support.reliableMarginRight=!parseFloat((window.getComputedStyle(marginDiv,null)||{}).marginRight);}
+body.removeChild(container);});return support;}({});var data_user,data_priv,rbrace=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,rmultiDash=/([A-Z])/g;function Data(){Object.defineProperty(this.cache={},0,{get:function(){return{};}});this.expando=jQuery.expando+Math.random();}
+Data.uid=1;Data.accepts=function(owner){return owner.nodeType?owner.nodeType===1||owner.nodeType===9:true;};Data.prototype={key:function(owner){if(!Data.accepts(owner)){return 0;}
+var descriptor={},unlock=owner[this.expando];if(!unlock){unlock=Data.uid++;try{descriptor[this.expando]={value:unlock};Object.defineProperties(owner,descriptor);}catch(e){descriptor[this.expando]=unlock;jQuery.extend(owner,descriptor);}}
+if(!this.cache[unlock]){this.cache[unlock]={};}
+return unlock;},set:function(owner,data,value){var prop,unlock=this.key(owner),cache=this.cache[unlock];if(typeof data==="string"){cache[data]=value;}else{if(jQuery.isEmptyObject(cache)){jQuery.extend(this.cache[unlock],data);}else{for(prop in data){cache[prop]=data[prop];}}}
+return cache;},get:function(owner,key){var cache=this.cache[this.key(owner)];return key===undefined?cache:cache[key];},access:function(owner,key,value){if(key===undefined||key&&typeof key==="string"&&value===undefined){return this.get(owner,key);}
+this.set(owner,key,value);return value!==undefined?value:key;},remove:function(owner,key){var i,name,camel,unlock=this.key(owner),cache=this.cache[unlock];if(key===undefined){this.cache[unlock]={};}else{if(jQuery.isArray(key)){name=key.concat(key.map(jQuery.camelCase));}else{camel=jQuery.camelCase(key);if(key in cache){name=[key,camel];}else{name=camel;name=name in cache?[name]:name.match(core_rnotwhite)||[];}}
+i=name.length;while(i--){delete cache[name[i]];}}},hasData:function(owner){return!jQuery.isEmptyObject(this.cache[owner[this.expando]]||{});},discard:function(owner){if(owner[this.expando]){delete this.cache[owner[this.expando]];}}};data_user=new Data;data_priv=new Data;jQuery.extend({acceptData:Data.accepts,hasData:function(elem){return data_user.hasData(elem)||data_priv.hasData(elem);},data:function(elem,name,data){return data_user.access(elem,name,data);},removeData:function(elem,name){data_user.remove(elem,name);},_data:function(elem,name,data){return data_priv.access(elem,name,data);},_removeData:function(elem,name){data_priv.remove(elem,name);}});jQuery.fn.extend({data:function(key,value){var attrs,name,elem=this[0],i=0,data=null;if(key===undefined){if(this.length){data=data_user.get(elem);if(elem.nodeType===1&&!data_priv.get(elem,"hasDataAttrs")){attrs=elem.attributes;for(;i<attrs.length;i++){name=attrs[i].name;if(name.indexOf("data-")===0){name=jQuery.camelCase(name.slice(5));dataAttr(elem,name,data[name]);}}
+data_priv.set(elem,"hasDataAttrs",true);}}
+return data;}
+if(typeof key==="object"){return this.each(function(){data_user.set(this,key);});}
+return jQuery.access(this,function(value){var data,camelKey=jQuery.camelCase(key);if(elem&&value===undefined){data=data_user.get(elem,key);if(data!==undefined){return data;}
+data=data_user.get(elem,camelKey);if(data!==undefined){return data;}
+data=dataAttr(elem,camelKey,undefined);if(data!==undefined){return data;}
+return;}
+this.each(function(){var data=data_user.get(this,camelKey);data_user.set(this,camelKey,value);if(key.indexOf("-")!==-1&&data!==undefined){data_user.set(this,key,value);}});},null,value,arguments.length>1,null,true);},removeData:function(key){return this.each(function(){data_user.remove(this,key);});}});function dataAttr(elem,key,data){var name;if(data===undefined&&elem.nodeType===1){name="data-"+key.replace(rmultiDash,"-$1").toLowerCase();data=elem.getAttribute(name);if(typeof data==="string"){try{data=data==="true"?true:data==="false"?false:data==="null"?null:+data+""===data?+data:rbrace.test(data)?JSON.parse(data):data;}catch(e){}
+data_user.set(elem,key,data);}else{data=undefined;}}
+return data;}
+jQuery.extend({queue:function(elem,type,data){var queue;if(elem){type=(type||"fx")+"queue";queue=data_priv.get(elem,type);if(data){if(!queue||jQuery.isArray(data)){queue=data_priv.access(elem,type,jQuery.makeArray(data));}else{queue.push(data);}}
+return queue||[];}},dequeue:function(elem,type){type=type||"fx";var queue=jQuery.queue(elem,type),startLength=queue.length,fn=queue.shift(),hooks=jQuery._queueHooks(elem,type),next=function(){jQuery.dequeue(elem,type);};if(fn==="inprogress"){fn=queue.shift();startLength--;}
+if(fn){if(type==="fx"){queue.unshift("inprogress");}
+delete hooks.stop;fn.call(elem,next,hooks);}
+if(!startLength&&hooks){hooks.empty.fire();}},_queueHooks:function(elem,type){var key=type+"queueHooks";return data_priv.get(elem,key)||data_priv.access(elem,key,{empty:jQuery.Callbacks("once memory").add(function(){data_priv.remove(elem,[type+"queue",key]);})});}});jQuery.fn.extend({queue:function(type,data){var setter=2;if(typeof type!=="string"){data=type;type="fx";setter--;}
+if(arguments.length<setter){return jQuery.queue(this[0],type);}
+return data===undefined?this:this.each(function(){var queue=jQuery.queue(this,type,data);jQuery._queueHooks(this,type);if(type==="fx"&&queue[0]!=="inprogress"){jQuery.dequeue(this,type);}});},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type);});},delay:function(time,type){time=jQuery.fx?jQuery.fx.speeds[time]||time:time;type=type||"fx";return this.queue(type,function(next,hooks){var timeout=setTimeout(next,time);hooks.stop=function(){clearTimeout(timeout);};});},clearQueue:function(type){return this.queue(type||"fx",[]);},promise:function(type,obj){var tmp,count=1,defer=jQuery.Deferred(),elements=this,i=this.length,resolve=function(){if(!--count){defer.resolveWith(elements,[elements]);}};if(typeof type!=="string"){obj=type;type=undefined;}
+type=type||"fx";while(i--){tmp=data_priv.get(elements[i],type+"queueHooks");if(tmp&&tmp.empty){count++;tmp.empty.add(resolve);}}
+resolve();return defer.promise(obj);}});var nodeHook,boolHook,rclass=/[\t\r\n\f]/g,rreturn=/\r/g,rfocusable=/^(?:input|select|textarea|button)$/i;jQuery.fn.extend({attr:function(name,value){return jQuery.access(this,jQuery.attr,name,value,arguments.length>1);},removeAttr:function(name){return this.each(function(){jQuery.removeAttr(this,name);});},prop:function(name,value){return jQuery.access(this,jQuery.prop,name,value,arguments.length>1);},removeProp:function(name){return this.each(function(){delete this[jQuery.propFix[name]||name];});},addClass:function(value){var classes,elem,cur,clazz,j,i=0,len=this.length,proceed=typeof value==="string"&&value;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).addClass(value.call(this,j,this.className));});}
+if(proceed){classes=(value||"").match(core_rnotwhite)||[];for(;i<len;i++){elem=this[i];cur=elem.nodeType===1&&(elem.className?(" "+elem.className+" ").replace(rclass," "):" ");if(cur){j=0;while(clazz=classes[j++]){if(cur.indexOf(" "+clazz+" ")<0){cur+=clazz+" ";}}
+elem.className=jQuery.trim(cur);}}}
+return this;},removeClass:function(value){var classes,elem,cur,clazz,j,i=0,len=this.length,proceed=arguments.length===0||typeof value==="string"&&value;if(jQuery.isFunction(value)){return this.each(function(j){jQuery(this).removeClass(value.call(this,j,this.className));});}
+if(proceed){classes=(value||"").match(core_rnotwhite)||[];for(;i<len;i++){elem=this[i];cur=elem.nodeType===1&&(elem.className?(" "+elem.className+" ").replace(rclass," "):"");if(cur){j=0;while(clazz=classes[j++]){while(cur.indexOf(" "+clazz+" ")>=0){cur=cur.replace(" "+clazz+" "," ");}}
+elem.className=value?jQuery.trim(cur):"";}}}
+return this;},toggleClass:function(value,stateVal){var type=typeof value,isBool=typeof stateVal==="boolean";if(jQuery.isFunction(value)){return this.each(function(i){jQuery(this).toggleClass(value.call(this,i,this.className,stateVal),stateVal);});}
+return this.each(function(){if(type==="string"){var className,i=0,self=jQuery(this),state=stateVal,classNames=value.match(core_rnotwhite)||[];while(className=classNames[i++]){state=isBool?state:!self.hasClass(className);self[state?"addClass":"removeClass"](className);}}else{if(type===core_strundefined||type==="boolean"){if(this.className){data_priv.set(this,"__className__",this.className);}
+this.className=this.className||value===false?"":data_priv.get(this,"__className__")||"";}}});},hasClass:function(selector){var className=" "+selector+" ",i=0,l=this.length;for(;i<l;i++){if(this[i].nodeType===1&&(" "+this[i].className+" ").replace(rclass," ").indexOf(className)>=0){return true;}}
+return false;},val:function(value){var hooks,ret,isFunction,elem=this[0];if(!arguments.length){if(elem){hooks=jQuery.valHooks[elem.type]||jQuery.valHooks[elem.nodeName.toLowerCase()];if(hooks&&"get"in hooks&&(ret=hooks.get(elem,"value"))!==undefined){return ret;}
+ret=elem.value;return typeof ret==="string"?ret.replace(rreturn,""):ret==null?"":ret;}
+return;}
+isFunction=jQuery.isFunction(value);return this.each(function(i){var val;if(this.nodeType!==1){return;}
+if(isFunction){val=value.call(this,i,jQuery(this).val());}else{val=value;}
+if(val==null){val="";}else{if(typeof val==="number"){val+="";}else{if(jQuery.isArray(val)){val=jQuery.map(val,function(value){return value==null?"":value+"";});}}}
+hooks=jQuery.valHooks[this.type]||jQuery.valHooks[this.nodeName.toLowerCase()];if(!hooks||!("set"in hooks)||hooks.set(this,val,"value")===undefined){this.value=val;}});}});jQuery.extend({valHooks:{option:{get:function(elem){var val=elem.attributes.value;return!val||val.specified?elem.value:elem.text;}},select:{get:function(elem){var value,option,options=elem.options,index=elem.selectedIndex,one=elem.type==="select-one"||index<0,values=one?null:[],max=one?index+1:options.length,i=index<0?max:one?index:0;for(;i<max;i++){option=options[i];if((option.selected||i===index)&&(jQuery.support.optDisabled?!option.disabled:option.getAttribute("disabled")===null)&&(!option.parentNode.disabled||!jQuery.nodeName(option.parentNode,"optgroup"))){value=jQuery(option).val();if(one){return value;}
+values.push(value);}}
+return values;},set:function(elem,value){var optionSet,option,options=elem.options,values=jQuery.makeArray(value),i=options.length;while(i--){option=options[i];if(option.selected=jQuery.inArray(jQuery(option).val(),values)>=0){optionSet=true;}}
+if(!optionSet){elem.selectedIndex=-1;}
+return values;}}},attr:function(elem,name,value){var hooks,ret,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return;}
+if(typeof elem.getAttribute===core_strundefined){return jQuery.prop(elem,name,value);}
+if(nType!==1||!jQuery.isXMLDoc(elem)){name=name.toLowerCase();hooks=jQuery.attrHooks[name]||(jQuery.expr.match.bool.test(name)?boolHook:nodeHook);}
+if(value!==undefined){if(value===null){jQuery.removeAttr(elem,name);}else{if(hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined){return ret;}else{elem.setAttribute(name,value+"");return value;}}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null){return ret;}else{ret=jQuery.find.attr(elem,name);return ret==null?undefined:ret;}}},removeAttr:function(elem,value){var name,propName,i=0,attrNames=value&&value.match(core_rnotwhite);if(attrNames&&elem.nodeType===1){while(name=attrNames[i++]){propName=jQuery.propFix[name]||name;if(jQuery.expr.match.bool.test(name)){elem[propName]=false;}
+elem.removeAttribute(name);}}},attrHooks:{type:{set:function(elem,value){if(!jQuery.support.radioValue&&value==="radio"&&jQuery.nodeName(elem,"input")){var val=elem.value;elem.setAttribute("type",value);if(val){elem.value=val;}
+return value;}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(elem,name,value){var ret,hooks,notxml,nType=elem.nodeType;if(!elem||nType===3||nType===8||nType===2){return;}
+notxml=nType!==1||!jQuery.isXMLDoc(elem);if(notxml){name=jQuery.propFix[name]||name;hooks=jQuery.propHooks[name];}
+if(value!==undefined){return hooks&&"set"in hooks&&(ret=hooks.set(elem,value,name))!==undefined?ret:elem[name]=value;}else{return hooks&&"get"in hooks&&(ret=hooks.get(elem,name))!==null?ret:elem[name];}},propHooks:{tabIndex:{get:function(elem){return elem.hasAttribute("tabindex")||rfocusable.test(elem.nodeName)||elem.href?elem.tabIndex:-1;}}}});boolHook={set:function(elem,value,name){if(value===false){jQuery.removeAttr(elem,name);}else{elem.setAttribute(name,name);}
+return name;}};jQuery.each(jQuery.expr.match.bool.source.match(/\w+/g),function(i,name){var getter=jQuery.expr.attrHandle[name]||jQuery.find.attr;jQuery.expr.attrHandle[name]=function(elem,name,isXML){var fn=jQuery.expr.attrHandle[name],ret=isXML?undefined:(jQuery.expr.attrHandle[name]=undefined)!=getter(elem,name,isXML)?name.toLowerCase():null;jQuery.expr.attrHandle[name]=fn;return ret;};});if(!jQuery.support.optSelected){jQuery.propHooks.selected={get:function(elem){var parent=elem.parentNode;if(parent&&parent.parentNode){parent.parentNode.selectedIndex;}
+return null;}};}
+jQuery.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){jQuery.propFix[this.toLowerCase()]=this;});jQuery.each(["radio","checkbox"],function(){jQuery.valHooks[this]={set:function(elem,value){if(jQuery.isArray(value)){return elem.checked=jQuery.inArray(jQuery(elem).val(),value)>=0;}}};if(!jQuery.support.checkOn){jQuery.valHooks[this].get=function(elem){return elem.getAttribute("value")===null?"on":elem.value;};}});var rkeyEvent=/^key/,rmouseEvent=/^(?:mouse|contextmenu)|click/,rfocusMorph=/^(?:focusinfocus|focusoutblur)$/,rtypenamespace=/^([^.]*)(?:\.(.+)|)$/;function returnTrue(){return true;}
+function returnFalse(){return false;}
+function safeActiveElement(){try{return document.activeElement;}catch(err){}}
+jQuery.event={global:{},add:function(elem,types,handler,data,selector){var handleObjIn,eventHandle,tmp,events,t,handleObj,special,handlers,type,namespaces,origType,elemData=data_priv.get(elem);if(!elemData){return;}
+if(handler.handler){handleObjIn=handler;handler=handleObjIn.handler;selector=handleObjIn.selector;}
+if(!handler.guid){handler.guid=jQuery.guid++;}
+if(!(events=elemData.events)){events=elemData.events={};}
+if(!(eventHandle=elemData.handle)){eventHandle=elemData.handle=function(e){return typeof jQuery!==core_strundefined&&(!e||jQuery.event.triggered!==e.type)?jQuery.event.dispatch.apply(eventHandle.elem,arguments):undefined;};eventHandle.elem=elem;}
+types=(types||"").match(core_rnotwhite)||[""];t=types.length;while(t--){tmp=rtypenamespace.exec(types[t])||[];type=origType=tmp[1];namespaces=(tmp[2]||"").split(".").sort();if(!type){continue;}
+special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;special=jQuery.event.special[type]||{};handleObj=jQuery.extend({type:type,origType:origType,data:data,handler:handler,guid:handler.guid,selector:selector,needsContext:selector&&jQuery.expr.match.needsContext.test(selector),namespace:namespaces.join(".")},handleObjIn);if(!(handlers=events[type])){handlers=events[type]=[];handlers.delegateCount=0;if(!special.setup||special.setup.call(elem,data,namespaces,eventHandle)===false){if(elem.addEventListener){elem.addEventListener(type,eventHandle,false);}}}
+if(special.add){special.add.call(elem,handleObj);if(!handleObj.handler.guid){handleObj.handler.guid=handler.guid;}}
+if(selector){handlers.splice(handlers.delegateCount++,0,handleObj);}else{handlers.push(handleObj);}
+jQuery.event.global[type]=true;}
+elem=null;},remove:function(elem,types,handler,selector,mappedTypes){var j,origCount,tmp,events,t,handleObj,special,handlers,type,namespaces,origType,elemData=data_priv.hasData(elem)&&data_priv.get(elem);if(!elemData||!(events=elemData.events)){return;}
+types=(types||"").match(core_rnotwhite)||[""];t=types.length;while(t--){tmp=rtypenamespace.exec(types[t])||[];type=origType=tmp[1];namespaces=(tmp[2]||"").split(".").sort();if(!type){for(type in events){jQuery.event.remove(elem,type+types[t],handler,selector,true);}
+continue;}
+special=jQuery.event.special[type]||{};type=(selector?special.delegateType:special.bindType)||type;handlers=events[type]||[];tmp=tmp[2]&&new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)");origCount=j=handlers.length;while(j--){handleObj=handlers[j];if((mappedTypes||origType===handleObj.origType)&&(!handler||handler.guid===handleObj.guid)&&(!tmp||tmp.test(handleObj.namespace))&&(!selector||selector===handleObj.selector||selector==="**"&&handleObj.selector)){handlers.splice(j,1);if(handleObj.selector){handlers.delegateCount--;}
+if(special.remove){special.remove.call(elem,handleObj);}}}
+if(origCount&&!handlers.length){if(!special.teardown||special.teardown.call(elem,namespaces,elemData.handle)===false){jQuery.removeEvent(elem,type,elemData.handle);}
+delete events[type];}}
+if(jQuery.isEmptyObject(events)){delete elemData.handle;data_priv.remove(elem,"events");}},trigger:function(event,data,elem,onlyHandlers){var i,cur,tmp,bubbleType,ontype,handle,special,eventPath=[elem||document],type=core_hasOwn.call(event,"type")?event.type:event,namespaces=core_hasOwn.call(event,"namespace")?event.namespace.split("."):[];cur=tmp=elem=elem||document;if(elem.nodeType===3||elem.nodeType===8){return;}
+if(rfocusMorph.test(type+jQuery.event.triggered)){return;}
+if(type.indexOf(".")>=0){namespaces=type.split(".");type=namespaces.shift();namespaces.sort();}
+ontype=type.indexOf(":")<0&&"on"+type;event=event[jQuery.expando]?event:new jQuery.Event(type,typeof event==="object"&&event);event.isTrigger=onlyHandlers?2:3;event.namespace=namespaces.join(".");event.namespace_re=event.namespace?new RegExp("(^|\\.)"+namespaces.join("\\.(?:.*\\.|)")+"(\\.|$)"):null;event.result=undefined;if(!event.target){event.target=elem;}
+data=data==null?[event]:jQuery.makeArray(data,[event]);special=jQuery.event.special[type]||{};if(!onlyHandlers&&special.trigger&&special.trigger.apply(elem,data)===false){return;}
+if(!onlyHandlers&&!special.noBubble&&!jQuery.isWindow(elem)){bubbleType=special.delegateType||type;if(!rfocusMorph.test(bubbleType+type)){cur=cur.parentNode;}
+for(;cur;cur=cur.parentNode){eventPath.push(cur);tmp=cur;}
+if(tmp===(elem.ownerDocument||document)){eventPath.push(tmp.defaultView||tmp.parentWindow||window);}}
+i=0;while((cur=eventPath[i++])&&!event.isPropagationStopped()){event.type=i>1?bubbleType:special.bindType||type;handle=(data_priv.get(cur,"events")||{})[event.type]&&data_priv.get(cur,"handle");if(handle){handle.apply(cur,data);}
+handle=ontype&&cur[ontype];if(handle&&jQuery.acceptData(cur)&&handle.apply&&handle.apply(cur,data)===false){event.preventDefault();}}
+event.type=type;if(!onlyHandlers&&!event.isDefaultPrevented()){if((!special._default||special._default.apply(eventPath.pop(),data)===false)&&jQuery.acceptData(elem)){if(ontype&&jQuery.isFunction(elem[type])&&!jQuery.isWindow(elem)){tmp=elem[ontype];if(tmp){elem[ontype]=null;}
+jQuery.event.triggered=type;elem[type]();jQuery.event.triggered=undefined;if(tmp){elem[ontype]=tmp;}}}}
+return event.result;},dispatch:function(event){event=jQuery.event.fix(event);var i,j,ret,matched,handleObj,handlerQueue=[],args=core_slice.call(arguments),handlers=(data_priv.get(this,"events")||{})[event.type]||[],special=jQuery.event.special[event.type]||{};args[0]=event;event.delegateTarget=this;if(special.preDispatch&&special.preDispatch.call(this,event)===false){return;}
+handlerQueue=jQuery.event.handlers.call(this,event,handlers);i=0;while((matched=handlerQueue[i++])&&!event.isPropagationStopped()){event.currentTarget=matched.elem;j=0;while((handleObj=matched.handlers[j++])&&!event.isImmediatePropagationStopped()){if(!event.namespace_re||event.namespace_re.test(handleObj.namespace)){event.handleObj=handleObj;event.data=handleObj.data;ret=((jQuery.event.special[handleObj.origType]||{}).handle||handleObj.handler).apply(matched.elem,args);if(ret!==undefined){if((event.result=ret)===false){event.preventDefault();event.stopPropagation();}}}}}
+if(special.postDispatch){special.postDispatch.call(this,event);}
+return event.result;},handlers:function(event,handlers){var i,matches,sel,handleObj,handlerQueue=[],delegateCount=handlers.delegateCount,cur=event.target;if(delegateCount&&cur.nodeType&&(!event.button||event.type!=="click")){for(;cur!==this;cur=cur.parentNode||this){if(cur.disabled!==true||event.type!=="click"){matches=[];for(i=0;i<delegateCount;i++){handleObj=handlers[i];sel=handleObj.selector+" ";if(matches[sel]===undefined){matches[sel]=handleObj.needsContext?jQuery(sel,this).index(cur)>=0:jQuery.find(sel,this,null,[cur]).length;}
+if(matches[sel]){matches.push(handleObj);}}
+if(matches.length){handlerQueue.push({elem:cur,handlers:matches});}}}}
+if(delegateCount<handlers.length){handlerQueue.push({elem:this,handlers:handlers.slice(delegateCount)});}
+return handlerQueue;},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(event,original){if(event.which==null){event.which=original.charCode!=null?original.charCode:original.keyCode;}
+return event;}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(event,original){var eventDoc,doc,body,button=original.button;if(event.pageX==null&&original.clientX!=null){eventDoc=event.target.ownerDocument||document;doc=eventDoc.documentElement;body=eventDoc.body;event.pageX=original.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc&&doc.clientLeft||body&&body.clientLeft||0);event.pageY=original.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc&&doc.clientTop||body&&body.clientTop||0);}
+if(!event.which&&button!==undefined){event.which=button&1?1:button&2?3:button&4?2:0;}
+return event;}},fix:function(event){if(event[jQuery.expando]){return event;}
+var i,prop,copy,type=event.type,originalEvent=event,fixHook=this.fixHooks[type];if(!fixHook){this.fixHooks[type]=fixHook=rmouseEvent.test(type)?this.mouseHooks:rkeyEvent.test(type)?this.keyHooks:{};}
+copy=fixHook.props?this.props.concat(fixHook.props):this.props;event=new jQuery.Event(originalEvent);i=copy.length;while(i--){prop=copy[i];event[prop]=originalEvent[prop];}
+if(!event.target){event.target=document;}
+if(event.target.nodeType===3){event.target=event.target.parentNode;}
+return fixHook.filter?fixHook.filter(event,originalEvent):event;},special:{load:{noBubble:true},focus:{trigger:function(){if(this!==safeActiveElement()&&this.focus){this.focus();return false;}},delegateType:"focusin"},blur:{trigger:function(){if(this===safeActiveElement()&&this.blur){this.blur();return false;}},delegateType:"focusout"},click:{trigger:function(){if(this.type==="checkbox"&&this.click&&jQuery.nodeName(this,"input")){this.click();return false;}},_default:function(event){return jQuery.nodeName(event.target,"a");}},beforeunload:{postDispatch:function(event){if(event.result!==undefined){event.originalEvent.returnValue=event.result;}}}},simulate:function(type,elem,event,bubble){var e=jQuery.extend(new jQuery.Event,event,{type:type,isSimulated:true,originalEvent:{}});if(bubble){jQuery.event.trigger(e,null,elem);}else{jQuery.event.dispatch.call(elem,e);}
+if(e.isDefaultPrevented()){event.preventDefault();}}};jQuery.removeEvent=function(elem,type,handle){if(elem.removeEventListener){elem.removeEventListener(type,handle,false);}};jQuery.Event=function(src,props){if(!(this instanceof jQuery.Event)){return new jQuery.Event(src,props);}
+if(src&&src.type){this.originalEvent=src;this.type=src.type;this.isDefaultPrevented=src.defaultPrevented||src.getPreventDefault&&src.getPreventDefault()?returnTrue:returnFalse;}else{this.type=src;}
+if(props){jQuery.extend(this,props);}
+this.timeStamp=src&&src.timeStamp||jQuery.now();this[jQuery.expando]=true;};jQuery.Event.prototype={isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=returnTrue;if(e&&e.preventDefault){e.preventDefault();}},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=returnTrue;if(e&&e.stopPropagation){e.stopPropagation();}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation();}};jQuery.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(orig,fix){jQuery.event.special[orig]={delegateType:fix,bindType:fix,handle:function(event){var ret,target=this,related=event.relatedTarget,handleObj=event.handleObj;if(!related||related!==target&&!jQuery.contains(target,related)){event.type=handleObj.origType;ret=handleObj.handler.apply(this,arguments);event.type=fix;}
+return ret;}};});if(!jQuery.support.focusinBubbles){jQuery.each({focus:"focusin",blur:"focusout"},function(orig,fix){var attaches=0,handler=function(event){jQuery.event.simulate(fix,event.target,jQuery.event.fix(event),true);};jQuery.event.special[fix]={setup:function(){if(attaches++===0){document.addEventListener(orig,handler,true);}},teardown:function(){if(--attaches===0){document.removeEventListener(orig,handler,true);}}};});}
+jQuery.fn.extend({on:function(types,selector,data,fn,one){var origFn,type;if(typeof types==="object"){if(typeof selector!=="string"){data=data||selector;selector=undefined;}
+for(type in types){this.on(type,selector,data,types[type],one);}
+return this;}
+if(data==null&&fn==null){fn=selector;data=selector=undefined;}else{if(fn==null){if(typeof selector==="string"){fn=data;data=undefined;}else{fn=data;data=selector;selector=undefined;}}}
+if(fn===false){fn=returnFalse;}else{if(!fn){return this;}}
+if(one===1){origFn=fn;fn=function(event){jQuery().off(event);return origFn.apply(this,arguments);};fn.guid=origFn.guid||(origFn.guid=jQuery.guid++);}
+return this.each(function(){jQuery.event.add(this,types,fn,data,selector);});},one:function(types,selector,data,fn){return this.on(types,selector,data,fn,1);},off:function(types,selector,fn){var handleObj,type;if(types&&types.preventDefault&&types.handleObj){handleObj=types.handleObj;jQuery(types.delegateTarget).off(handleObj.namespace?handleObj.origType+"."+handleObj.namespace:handleObj.origType,handleObj.selector,handleObj.handler);return this;}
+if(typeof types==="object"){for(type in types){this.off(type,selector,types[type]);}
+return this;}
+if(selector===false||typeof selector==="function"){fn=selector;selector=undefined;}
+if(fn===false){fn=returnFalse;}
+return this.each(function(){jQuery.event.remove(this,types,fn,selector);});},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this);});},triggerHandler:function(type,data){var elem=this[0];if(elem){return jQuery.event.trigger(type,data,elem,true);}}});var isSimple=/^.[^:#\[\.,]*$/,rparentsprev=/^(?:parents|prev(?:Until|All))/,rneedsContext=jQuery.expr.match.needsContext,guaranteedUnique={children:true,contents:true,next:true,prev:true};jQuery.fn.extend({find:function(selector){var i,ret=[],self=this,len=self.length;if(typeof selector!=="string"){return this.pushStack(jQuery(selector).filter(function(){for(i=0;i<len;i++){if(jQuery.contains(self[i],this)){return true;}}}));}
+for(i=0;i<len;i++){jQuery.find(selector,self[i],ret);}
+ret=this.pushStack(len>1?jQuery.unique(ret):ret);ret.selector=this.selector?this.selector+" "+selector:selector;return ret;},has:function(target){var targets=jQuery(target,this),l=targets.length;return this.filter(function(){var i=0;for(;i<l;i++){if(jQuery.contains(this,targets[i])){return true;}}});},not:function(selector){return this.pushStack(winnow(this,selector||[],true));},filter:function(selector){return this.pushStack(winnow(this,selector||[],false));},is:function(selector){return!!winnow(this,typeof selector==="string"&&rneedsContext.test(selector)?jQuery(selector):selector||[],false).length;},closest:function(selectors,context){var cur,i=0,l=this.length,matched=[],pos=rneedsContext.test(selectors)||typeof selectors!=="string"?jQuery(selectors,context||this.context):0;for(;i<l;i++){for(cur=this[i];cur&&cur!==context;cur=cur.parentNode){if(cur.nodeType<11&&(pos?pos.index(cur)>-1:cur.nodeType===1&&jQuery.find.matchesSelector(cur,selectors))){cur=matched.push(cur);break;}}}
+return this.pushStack(matched.length>1?jQuery.unique(matched):matched);},index:function(elem){if(!elem){return this[0]&&this[0].parentNode?this.first().prevAll().length:-1;}
+if(typeof elem==="string"){return core_indexOf.call(jQuery(elem),this[0]);}
+return core_indexOf.call(this,elem.jquery?elem[0]:elem);},add:function(selector,context){var set=typeof selector==="string"?jQuery(selector,context):jQuery.makeArray(selector&&selector.nodeType?[selector]:selector),all=jQuery.merge(this.get(),set);return this.pushStack(jQuery.unique(all));},addBack:function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector));}});function sibling(cur,dir){while((cur=cur[dir])&&cur.nodeType!==1){}
+return cur;}
+jQuery.each({parent:function(elem){var parent=elem.parentNode;return parent&&parent.nodeType!==11?parent:null;},parents:function(elem){return jQuery.dir(elem,"parentNode");},parentsUntil:function(elem,i,until){return jQuery.dir(elem,"parentNode",until);},next:function(elem){return sibling(elem,"nextSibling");},prev:function(elem){return sibling(elem,"previousSibling");},nextAll:function(elem){return jQuery.dir(elem,"nextSibling");},prevAll:function(elem){return jQuery.dir(elem,"previousSibling");},nextUntil:function(elem,i,until){return jQuery.dir(elem,"nextSibling",until);},prevUntil:function(elem,i,until){return jQuery.dir(elem,"previousSibling",until);},siblings:function(elem){return jQuery.sibling((elem.parentNode||{}).firstChild,elem);},children:function(elem){return jQuery.sibling(elem.firstChild);},contents:function(elem){return elem.contentDocument||jQuery.merge([],elem.childNodes);}},function(name,fn){jQuery.fn[name]=function(until,selector){var matched=jQuery.map(this,fn,until);if(name.slice(-5)!=="Until"){selector=until;}
+if(selector&&typeof selector==="string"){matched=jQuery.filter(selector,matched);}
+if(this.length>1){if(!guaranteedUnique[name]){jQuery.unique(matched);}
+if(rparentsprev.test(name)){matched.reverse();}}
+return this.pushStack(matched);};});jQuery.extend({filter:function(expr,elems,not){var elem=elems[0];if(not){expr=":not("+expr+")";}
+return elems.length===1&&elem.nodeType===1?jQuery.find.matchesSelector(elem,expr)?[elem]:[]:jQuery.find.matches(expr,jQuery.grep(elems,function(elem){return elem.nodeType===1;}));},dir:function(elem,dir,until){var matched=[],truncate=until!==undefined;while((elem=elem[dir])&&elem.nodeType!==9){if(elem.nodeType===1){if(truncate&&jQuery(elem).is(until)){break;}
+matched.push(elem);}}
+return matched;},sibling:function(n,elem){var matched=[];for(;n;n=n.nextSibling){if(n.nodeType===1&&n!==elem){matched.push(n);}}
+return matched;}});function winnow(elements,qualifier,not){if(jQuery.isFunction(qualifier)){return jQuery.grep(elements,function(elem,i){return!!qualifier.call(elem,i,elem)!==not;});}
+if(qualifier.nodeType){return jQuery.grep(elements,function(elem){return elem===qualifier!==not;});}
+if(typeof qualifier==="string"){if(isSimple.test(qualifier)){return jQuery.filter(qualifier,elements,not);}
+qualifier=jQuery.filter(qualifier,elements);}
+return jQuery.grep(elements,function(elem){return core_indexOf.call(qualifier,elem)>=0!==not;});}
+var rxhtmlTag=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,rtagName=/<([\w:]+)/,rhtml=/<|&#?\w+;/,rnoInnerhtml=/<(?:script|style|link)/i,manipulation_rcheckableType=/^(?:checkbox|radio)$/i,rchecked=/checked\s*(?:[^=]|=\s*.checked.)/i,rscriptType=/^$|\/(?:java|ecma)script/i,rscriptTypeMasked=/^true\/(.*)/,rcleanScript=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,wrapMap={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};wrapMap.optgroup=wrapMap.option;wrapMap.tbody=wrapMap.tfoot=wrapMap.colgroup=wrapMap.caption=wrapMap.thead;wrapMap.th=wrapMap.td;jQuery.fn.extend({text:function(value){return jQuery.access(this,function(value){return value===undefined?jQuery.text(this):this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(value));},null,value,arguments.length);},append:function(){return this.domManip(arguments,function(elem){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var target=manipulationTarget(this,elem);target.appendChild(elem);}});},prepend:function(){return this.domManip(arguments,function(elem){if(this.nodeType===1||this.nodeType===11||this.nodeType===9){var target=manipulationTarget(this,elem);target.insertBefore(elem,target.firstChild);}});},before:function(){return this.domManip(arguments,function(elem){if(this.parentNode){this.parentNode.insertBefore(elem,this);}});},after:function(){return this.domManip(arguments,function(elem){if(this.parentNode){this.parentNode.insertBefore(elem,this.nextSibling);}});},remove:function(selector,keepData){var elem,elems=selector?jQuery.filter(selector,this):this,i=0;for(;(elem=elems[i])!=null;i++){if(!keepData&&elem.nodeType===1){jQuery.cleanData(getAll(elem));}
+if(elem.parentNode){if(keepData&&jQuery.contains(elem.ownerDocument,elem)){setGlobalEval(getAll(elem,"script"));}
+elem.parentNode.removeChild(elem);}}
+return this;},empty:function(){var elem,i=0;for(;(elem=this[i])!=null;i++){if(elem.nodeType===1){jQuery.cleanData(getAll(elem,false));elem.textContent="";}}
+return this;},clone:function(dataAndEvents,deepDataAndEvents){dataAndEvents=dataAndEvents==null?false:dataAndEvents;deepDataAndEvents=deepDataAndEvents==null?dataAndEvents:deepDataAndEvents;return this.map(function(){return jQuery.clone(this,dataAndEvents,deepDataAndEvents);});},html:function(value){return jQuery.access(this,function(value){var elem=this[0]||{},i=0,l=this.length;if(value===undefined&&elem.nodeType===1){return elem.innerHTML;}
+if(typeof value==="string"&&!rnoInnerhtml.test(value)&&!wrapMap[(rtagName.exec(value)||["",""])[1].toLowerCase()]){value=value.replace(rxhtmlTag,"<$1></$2>");try{for(;i<l;i++){elem=this[i]||{};if(elem.nodeType===1){jQuery.cleanData(getAll(elem,false));elem.innerHTML=value;}}
+elem=0;}catch(e){}}
+if(elem){this.empty().append(value);}},null,value,arguments.length);},replaceWith:function(){var args=jQuery.map(this,function(elem){return[elem.nextSibling,elem.parentNode];}),i=0;this.domManip(arguments,function(elem){var next=args[i++],parent=args[i++];if(parent){if(next&&next.parentNode!==parent){next=this.nextSibling;}
+jQuery(this).remove();parent.insertBefore(elem,next);}},true);return i?this:this.remove();},detach:function(selector){return this.remove(selector,true);},domManip:function(args,callback,allowIntersection){args=core_concat.apply([],args);var fragment,first,scripts,hasScripts,node,doc,i=0,l=this.length,set=this,iNoClone=l-1,value=args[0],isFunction=jQuery.isFunction(value);if(isFunction||!(l<=1||typeof value!=="string"||jQuery.support.checkClone||!rchecked.test(value))){return this.each(function(index){var self=set.eq(index);if(isFunction){args[0]=value.call(this,index,self.html());}
+self.domManip(args,callback,allowIntersection);});}
+if(l){fragment=jQuery.buildFragment(args,this[0].ownerDocument,false,!allowIntersection&&this);first=fragment.firstChild;if(fragment.childNodes.length===1){fragment=first;}
+if(first){scripts=jQuery.map(getAll(fragment,"script"),disableScript);hasScripts=scripts.length;for(;i<l;i++){node=fragment;if(i!==iNoClone){node=jQuery.clone(node,true,true);if(hasScripts){jQuery.merge(scripts,getAll(node,"script"));}}
+callback.call(this[i],node,i);}
+if(hasScripts){doc=scripts[scripts.length-1].ownerDocument;jQuery.map(scripts,restoreScript);for(i=0;i<hasScripts;i++){node=scripts[i];if(rscriptType.test(node.type||"")&&!data_priv.access(node,"globalEval")&&jQuery.contains(doc,node)){if(node.src){jQuery._evalUrl(node.src);}else{jQuery.globalEval(node.textContent.replace(rcleanScript,""));}}}}}}
+return this;}});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var elems,ret=[],insert=jQuery(selector),last=insert.length-1,i=0;for(;i<=last;i++){elems=i===last?this:this.clone(true);jQuery(insert[i])[original](elems);core_push.apply(ret,elems.get());}
+return this.pushStack(ret);};});jQuery.extend({clone:function(elem,dataAndEvents,deepDataAndEvents){var i,l,srcElements,destElements,clone=elem.cloneNode(true),inPage=jQuery.contains(elem.ownerDocument,elem);if(!jQuery.support.noCloneChecked&&(elem.nodeType===1||elem.nodeType===11)&&!jQuery.isXMLDoc(elem)){destElements=getAll(clone);srcElements=getAll(elem);for(i=0,l=srcElements.length;i<l;i++){fixInput(srcElements[i],destElements[i]);}}
+if(dataAndEvents){if(deepDataAndEvents){srcElements=srcElements||getAll(elem);destElements=destElements||getAll(clone);for(i=0,l=srcElements.length;i<l;i++){cloneCopyEvent(srcElements[i],destElements[i]);}}else{cloneCopyEvent(elem,clone);}}
+destElements=getAll(clone,"script");if(destElements.length>0){setGlobalEval(destElements,!inPage&&getAll(elem,"script"));}
+return clone;},buildFragment:function(elems,context,scripts,selection){var elem,tmp,tag,wrap,contains,j,i=0,l=elems.length,fragment=context.createDocumentFragment(),nodes=[];for(;i<l;i++){elem=elems[i];if(elem||elem===0){if(jQuery.type(elem)==="object"){jQuery.merge(nodes,elem.nodeType?[elem]:elem);}else{if(!rhtml.test(elem)){nodes.push(context.createTextNode(elem));}else{tmp=tmp||fragment.appendChild(context.createElement("div"));tag=(rtagName.exec(elem)||["",""])[1].toLowerCase();wrap=wrapMap[tag]||wrapMap._default;tmp.innerHTML=wrap[1]+elem.replace(rxhtmlTag,"<$1></$2>")+wrap[2];j=wrap[0];while(j--){tmp=tmp.firstChild;}
+jQuery.merge(nodes,tmp.childNodes);tmp=fragment.firstChild;tmp.textContent="";}}}}
+fragment.textContent="";i=0;while(elem=nodes[i++]){if(selection&&jQuery.inArray(elem,selection)!==-1){continue;}
+contains=jQuery.contains(elem.ownerDocument,elem);tmp=getAll(fragment.appendChild(elem),"script");if(contains){setGlobalEval(tmp);}
+if(scripts){j=0;while(elem=tmp[j++]){if(rscriptType.test(elem.type||"")){scripts.push(elem);}}}}
+return fragment;},cleanData:function(elems){var data,elem,events,type,key,j,special=jQuery.event.special,i=0;for(;(elem=elems[i])!==undefined;i++){if(Data.accepts(elem)){key=elem[data_priv.expando];if(key&&(data=data_priv.cache[key])){events=Object.keys(data.events||{});if(events.length){for(j=0;(type=events[j])!==undefined;j++){if(special[type]){jQuery.event.remove(elem,type);}else{jQuery.removeEvent(elem,type,data.handle);}}}
+if(data_priv.cache[key]){delete data_priv.cache[key];}}}
+delete data_user.cache[elem[data_user.expando]];}},_evalUrl:function(url){return jQuery.ajax({url:url,type:"GET",dataType:"script",async:false,global:false,"throws":true});}});function manipulationTarget(elem,content){return jQuery.nodeName(elem,"table")&&jQuery.nodeName(content.nodeType===1?content:content.firstChild,"tr")?elem.getElementsByTagName("tbody")[0]||elem.appendChild(elem.ownerDocument.createElement("tbody")):elem;}
+function disableScript(elem){elem.type=(elem.getAttribute("type")!==null)+"/"+elem.type;return elem;}
+function restoreScript(elem){var match=rscriptTypeMasked.exec(elem.type);if(match){elem.type=match[1];}else{elem.removeAttribute("type");}
+return elem;}
+function setGlobalEval(elems,refElements){var l=elems.length,i=0;for(;i<l;i++){data_priv.set(elems[i],"globalEval",!refElements||data_priv.get(refElements[i],"globalEval"));}}
+function cloneCopyEvent(src,dest){var i,l,type,pdataOld,pdataCur,udataOld,udataCur,events;if(dest.nodeType!==1){return;}
+if(data_priv.hasData(src)){pdataOld=data_priv.access(src);pdataCur=data_priv.set(dest,pdataOld);events=pdataOld.events;if(events){delete pdataCur.handle;pdataCur.events={};for(type in events){for(i=0,l=events[type].length;i<l;i++){jQuery.event.add(dest,type,events[type][i]);}}}}
+if(data_user.hasData(src)){udataOld=data_user.access(src);udataCur=jQuery.extend({},udataOld);data_user.set(dest,udataCur);}}
+function getAll(context,tag){var ret=context.getElementsByTagName?context.getElementsByTagName(tag||"*"):context.querySelectorAll?context.querySelectorAll(tag||"*"):[];return tag===undefined||tag&&jQuery.nodeName(context,tag)?jQuery.merge([context],ret):ret;}
+function fixInput(src,dest){var nodeName=dest.nodeName.toLowerCase();if(nodeName==="input"&&manipulation_rcheckableType.test(src.type)){dest.checked=src.checked;}else{if(nodeName==="input"||nodeName==="textarea"){dest.defaultValue=src.defaultValue;}}}
+jQuery.fn.extend({wrapAll:function(html){var wrap;if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapAll(html.call(this,i));});}
+if(this[0]){wrap=jQuery(html,this[0].ownerDocument).eq(0).clone(true);if(this[0].parentNode){wrap.insertBefore(this[0]);}
+wrap.map(function(){var elem=this;while(elem.firstElementChild){elem=elem.firstElementChild;}
+return elem;}).append(this);}
+return this;},wrapInner:function(html){if(jQuery.isFunction(html)){return this.each(function(i){jQuery(this).wrapInner(html.call(this,i));});}
+return this.each(function(){var self=jQuery(this),contents=self.contents();if(contents.length){contents.wrapAll(html);}else{self.append(html);}});},wrap:function(html){var isFunction=jQuery.isFunction(html);return this.each(function(i){jQuery(this).wrapAll(isFunction?html.call(this,i):html);});},unwrap:function(){return this.parent().each(function(){if(!jQuery.nodeName(this,"body")){jQuery(this).replaceWith(this.childNodes);}}).end();}});var curCSS,iframe,rdisplayswap=/^(none|table(?!-c[ea]).+)/,rmargin=/^margin/,rnumsplit=new RegExp("^("+core_pnum+")(.*)$","i"),rnumnonpx=new RegExp("^("+core_pnum+")(?!px)[a-z%]+$","i"),rrelNum=new RegExp("^([+-])=("+core_pnum+")","i"),elemdisplay={BODY:"block"},cssShow={position:"absolute",visibility:"hidden",display:"block"},cssNormalTransform={letterSpacing:0,fontWeight:400},cssExpand=["Top","Right","Bottom","Left"],cssPrefixes=["Webkit","O","Moz","ms"];function vendorPropName(style,name){if(name in style){return name;}
+var capName=name.charAt(0).toUpperCase()+name.slice(1),origName=name,i=cssPrefixes.length;while(i--){name=cssPrefixes[i]+capName;if(name in style){return name;}}
+return origName;}
+function isHidden(elem,el){elem=el||elem;return jQuery.css(elem,"display")==="none"||!jQuery.contains(elem.ownerDocument,elem);}
+function getStyles(elem){return window.getComputedStyle(elem,null);}
+function showHide(elements,show){var display,elem,hidden,values=[],index=0,length=elements.length;for(;index<length;index++){elem=elements[index];if(!elem.style){continue;}
+values[index]=data_priv.get(elem,"olddisplay");display=elem.style.display;if(show){if(!values[index]&&display==="none"){elem.style.display="";}
+if(elem.style.display===""&&isHidden(elem)){values[index]=data_priv.access(elem,"olddisplay",css_defaultDisplay(elem.nodeName));}}else{if(!values[index]){hidden=isHidden(elem);if(display&&display!=="none"||!hidden){data_priv.set(elem,"olddisplay",hidden?display:jQuery.css(elem,"display"));}}}}
+for(index=0;index<length;index++){elem=elements[index];if(!elem.style){continue;}
+if(!show||elem.style.display==="none"||elem.style.display===""){elem.style.display=show?values[index]||"":"none";}}
+return elements;}
+jQuery.fn.extend({css:function(name,value){return jQuery.access(this,function(elem,name,value){var styles,len,map={},i=0;if(jQuery.isArray(name)){styles=getStyles(elem);len=name.length;for(;i<len;i++){map[name[i]]=jQuery.css(elem,name[i],false,styles);}
+return map;}
+return value!==undefined?jQuery.style(elem,name,value):jQuery.css(elem,name);},name,value,arguments.length>1);},show:function(){return showHide(this,true);},hide:function(){return showHide(this);},toggle:function(state){var bool=typeof state==="boolean";return this.each(function(){if(bool?state:isHidden(this)){jQuery(this).show();}else{jQuery(this).hide();}});}});jQuery.extend({cssHooks:{opacity:{get:function(elem,computed){if(computed){var ret=curCSS(elem,"opacity");return ret===""?"1":ret;}}}},cssNumber:{"columnCount":true,"fillOpacity":true,"fontWeight":true,"lineHeight":true,"opacity":true,"orphans":true,"widows":true,"zIndex":true,"zoom":true},cssProps:{"float":"cssFloat"},style:function(elem,name,value,extra){if(!elem||elem.nodeType===3||elem.nodeType===8||!elem.style){return;}
+var ret,type,hooks,origName=jQuery.camelCase(name),style=elem.style;name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(value!==undefined){type=typeof value;if(type==="string"&&(ret=rrelNum.exec(value))){value=(ret[1]+1)*ret[2]+parseFloat(jQuery.css(elem,name));type="number";}
+if(value==null||type==="number"&&isNaN(value)){return;}
+if(type==="number"&&!jQuery.cssNumber[origName]){value+="px";}
+if(!jQuery.support.clearCloneStyle&&value===""&&name.indexOf("background")===0){style[name]="inherit";}
+if(!hooks||!("set"in hooks)||(value=hooks.set(elem,value,extra))!==undefined){style[name]=value;}}else{if(hooks&&"get"in hooks&&(ret=hooks.get(elem,false,extra))!==undefined){return ret;}
+return style[name];}},css:function(elem,name,extra,styles){var val,num,hooks,origName=jQuery.camelCase(name);name=jQuery.cssProps[origName]||(jQuery.cssProps[origName]=vendorPropName(elem.style,origName));hooks=jQuery.cssHooks[name]||jQuery.cssHooks[origName];if(hooks&&"get"in hooks){val=hooks.get(elem,true,extra);}
+if(val===undefined){val=curCSS(elem,name,styles);}
+if(val==="normal"&&name in cssNormalTransform){val=cssNormalTransform[name];}
+if(extra===""||extra){num=parseFloat(val);return extra===true||jQuery.isNumeric(num)?num||0:val;}
+return val;}});curCSS=function(elem,name,_computed){var width,minWidth,maxWidth,computed=_computed||getStyles(elem),ret=computed?computed.getPropertyValue(name)||computed[name]:undefined,style=elem.style;if(computed){if(ret===""&&!jQuery.contains(elem.ownerDocument,elem)){ret=jQuery.style(elem,name);}
+if(rnumnonpx.test(ret)&&rmargin.test(name)){width=style.width;minWidth=style.minWidth;maxWidth=style.maxWidth;style.minWidth=style.maxWidth=style.width=ret;ret=computed.width;style.width=width;style.minWidth=minWidth;style.maxWidth=maxWidth;}}
+return ret;};function setPositiveNumber(elem,value,subtract){var matches=rnumsplit.exec(value);return matches?Math.max(0,matches[1]-(subtract||0))+(matches[2]||"px"):value;}
+function augmentWidthOrHeight(elem,name,extra,isBorderBox,styles){var i=extra===(isBorderBox?"border":"content")?4:name==="width"?1:0,val=0;for(;i<4;i+=2){if(extra==="margin"){val+=jQuery.css(elem,extra+cssExpand[i],true,styles);}
+if(isBorderBox){if(extra==="content"){val-=jQuery.css(elem,"padding"+cssExpand[i],true,styles);}
+if(extra!=="margin"){val-=jQuery.css(elem,"border"+cssExpand[i]+"Width",true,styles);}}else{val+=jQuery.css(elem,"padding"+cssExpand[i],true,styles);if(extra!=="padding"){val+=jQuery.css(elem,"border"+cssExpand[i]+"Width",true,styles);}}}
+return val;}
+function getWidthOrHeight(elem,name,extra){var valueIsBorderBox=true,val=name==="width"?elem.offsetWidth:elem.offsetHeight,styles=getStyles(elem),isBorderBox=jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing",false,styles)==="border-box";if(val<=0||val==null){val=curCSS(elem,name,styles);if(val<0||val==null){val=elem.style[name];}
+if(rnumnonpx.test(val)){return val;}
+valueIsBorderBox=isBorderBox&&(jQuery.support.boxSizingReliable||val===elem.style[name]);val=parseFloat(val)||0;}
+return val+augmentWidthOrHeight(elem,name,extra||(isBorderBox?"border":"content"),valueIsBorderBox,styles)+"px";}
+function css_defaultDisplay(nodeName){var doc=document,display=elemdisplay[nodeName];if(!display){display=actualDisplay(nodeName,doc);if(display==="none"||!display){iframe=(iframe||jQuery("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(doc.documentElement);doc=(iframe[0].contentWindow||iframe[0].contentDocument).document;doc.write("<!doctype html><html><body>");doc.close();display=actualDisplay(nodeName,doc);iframe.detach();}
+elemdisplay[nodeName]=display;}
+return display;}
+function actualDisplay(name,doc){var elem=jQuery(doc.createElement(name)).appendTo(doc.body),display=jQuery.css(elem[0],"display");elem.remove();return display;}
+jQuery.each(["height","width"],function(i,name){jQuery.cssHooks[name]={get:function(elem,computed,extra){if(computed){return elem.offsetWidth===0&&rdisplayswap.test(jQuery.css(elem,"display"))?jQuery.swap(elem,cssShow,function(){return getWidthOrHeight(elem,name,extra);}):getWidthOrHeight(elem,name,extra);}},set:function(elem,value,extra){var styles=extra&&getStyles(elem);return setPositiveNumber(elem,value,extra?augmentWidthOrHeight(elem,name,extra,jQuery.support.boxSizing&&jQuery.css(elem,"boxSizing",false,styles)==="border-box",styles):0);}};});jQuery(function(){if(!jQuery.support.reliableMarginRight){jQuery.cssHooks.marginRight={get:function(elem,computed){if(computed){return jQuery.swap(elem,{"display":"inline-block"},curCSS,[elem,"marginRight"]);}}};}
+if(!jQuery.support.pixelPosition&&jQuery.fn.position){jQuery.each(["top","left"],function(i,prop){jQuery.cssHooks[prop]={get:function(elem,computed){if(computed){computed=curCSS(elem,prop);return rnumnonpx.test(computed)?jQuery(elem).position()[prop]+"px":computed;}}};});}});if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.hidden=function(elem){return elem.offsetWidth<=0&&elem.offsetHeight<=0;};jQuery.expr.filters.visible=function(elem){return!jQuery.expr.filters.hidden(elem);};}
+jQuery.each({margin:"",padding:"",border:"Width"},function(prefix,suffix){jQuery.cssHooks[prefix+suffix]={expand:function(value){var i=0,expanded={},parts=typeof value==="string"?value.split(" "):[value];for(;i<4;i++){expanded[prefix+cssExpand[i]+suffix]=parts[i]||parts[i-2]||parts[0];}
+return expanded;}};if(!rmargin.test(prefix)){jQuery.cssHooks[prefix+suffix].set=setPositiveNumber;}});var r20=/%20/g,rbracket=/\[\]$/,rCRLF=/\r?\n/g,rsubmitterTypes=/^(?:submit|button|image|reset|file)$/i,rsubmittable=/^(?:input|select|textarea|keygen)/i;jQuery.fn.extend({serialize:function(){return jQuery.param(this.serializeArray());},serializeArray:function(){return this.map(function(){var elements=jQuery.prop(this,"elements");return elements?jQuery.makeArray(elements):this;}).filter(function(){var type=this.type;return this.name&&!jQuery(this).is(":disabled")&&rsubmittable.test(this.nodeName)&&!rsubmitterTypes.test(type)&&(this.checked||!manipulation_rcheckableType.test(type));}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val){return{name:elem.name,value:val.replace(rCRLF,"\r\n")};}):{name:elem.name,value:val.replace(rCRLF,"\r\n")};}).get();}});jQuery.param=function(a,traditional){var prefix,s=[],add=function(key,value){value=jQuery.isFunction(value)?value():value==null?"":value;s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value);};if(traditional===undefined){traditional=jQuery.ajaxSettings&&jQuery.ajaxSettings.traditional;}
+if(jQuery.isArray(a)||a.jquery&&!jQuery.isPlainObject(a)){jQuery.each(a,function(){add(this.name,this.value);});}else{for(prefix in a){buildParams(prefix,a[prefix],traditional,add);}}
+return s.join("&").replace(r20,"+");};function buildParams(prefix,obj,traditional,add){var name;if(jQuery.isArray(obj)){jQuery.each(obj,function(i,v){if(traditional||rbracket.test(prefix)){add(prefix,v);}else{buildParams(prefix+"["+(typeof v==="object"?i:"")+"]",v,traditional,add);}});}else{if(!traditional&&jQuery.type(obj)==="object"){for(name in obj){buildParams(prefix+"["+name+"]",obj[name],traditional,add);}}else{add(prefix,obj);}}}
+jQuery.each(("blur focus focusin focusout load resize scroll unload click dblclick "+"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave "+"change select submit keydown keypress keyup error contextmenu").split(" "),function(i,name){jQuery.fn[name]=function(data,fn){return arguments.length>0?this.on(name,null,data,fn):this.trigger(name);};});jQuery.fn.extend({hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut||fnOver);},bind:function(types,data,fn){return this.on(types,null,data,fn);},unbind:function(types,fn){return this.off(types,null,fn);},delegate:function(selector,types,data,fn){return this.on(types,selector,data,fn);},undelegate:function(selector,types,fn){return arguments.length===1?this.off(selector,"**"):this.off(types,selector||"**",fn);}});var ajaxLocParts,ajaxLocation,ajax_nonce=jQuery.now(),ajax_rquery=/\?/,rhash=/#.*$/,rts=/([?&])_=[^&]*/,rheaders=/^(.*?):[ \t]*([^\r\n]*)$/mg,rlocalProtocol=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,rnoContent=/^(?:GET|HEAD)$/,rprotocol=/^\/\//,rurl=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,_load=jQuery.fn.load,prefilters={},transports={},allTypes="*/".concat("*");try{ajaxLocation=location.href;}catch(e){ajaxLocation=document.createElement("a");ajaxLocation.href="";ajaxLocation=ajaxLocation.href;}
+ajaxLocParts=rurl.exec(ajaxLocation.toLowerCase())||[];function addToPrefiltersOrTransports(structure){return function(dataTypeExpression,func){if(typeof dataTypeExpression!=="string"){func=dataTypeExpression;dataTypeExpression="*";}
+var dataType,i=0,dataTypes=dataTypeExpression.toLowerCase().match(core_rnotwhite)||[];if(jQuery.isFunction(func)){while(dataType=dataTypes[i++]){if(dataType[0]==="+"){dataType=dataType.slice(1)||"*";(structure[dataType]=structure[dataType]||[]).unshift(func);}else{(structure[dataType]=structure[dataType]||[]).push(func);}}}};}
+function inspectPrefiltersOrTransports(structure,options,originalOptions,jqXHR){var inspected={},seekingTransport=structure===transports;function inspect(dataType){var selected;inspected[dataType]=true;jQuery.each(structure[dataType]||[],function(_,prefilterOrFactory){var dataTypeOrTransport=prefilterOrFactory(options,originalOptions,jqXHR);if(typeof dataTypeOrTransport==="string"&&!seekingTransport&&!inspected[dataTypeOrTransport]){options.dataTypes.unshift(dataTypeOrTransport);inspect(dataTypeOrTransport);return false;}else{if(seekingTransport){return!(selected=dataTypeOrTransport);}}});return selected;}
+return inspect(options.dataTypes[0])||!inspected["*"]&&inspect("*");}
+function ajaxExtend(target,src){var key,deep,flatOptions=jQuery.ajaxSettings.flatOptions||{};for(key in src){if(src[key]!==undefined){(flatOptions[key]?target:deep||(deep={}))[key]=src[key];}}
+if(deep){jQuery.extend(true,target,deep);}
+return target;}
+jQuery.fn.load=function(url,params,callback){if(typeof url!=="string"&&_load){return _load.apply(this,arguments);}
+var selector,type,response,self=this,off=url.indexOf(" ");if(off>=0){selector=url.slice(off);url=url.slice(0,off);}
+if(jQuery.isFunction(params)){callback=params;params=undefined;}else{if(params&&typeof params==="object"){type="POST";}}
+if(self.length>0){jQuery.ajax({url:url,type:type,dataType:"html",data:params}).done(function(responseText){response=arguments;self.html(selector?jQuery("<div>").append(jQuery.parseHTML(responseText)).find(selector):responseText);}).complete(callback&&function(jqXHR,status){self.each(callback,response||[jqXHR.responseText,status,jqXHR]);});}
+return this;};jQuery.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(i,type){jQuery.fn[type]=function(fn){return this.on(type,fn);};});jQuery.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:ajaxLocation,type:"GET",isLocal:rlocalProtocol.test(ajaxLocParts[1]),global:true,processData:true,async:true,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":allTypes,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":true,"text json":jQuery.parseJSON,"text xml":jQuery.parseXML},flatOptions:{url:true,context:true}},ajaxSetup:function(target,settings){return settings?ajaxExtend(ajaxExtend(target,jQuery.ajaxSettings),settings):ajaxExtend(jQuery.ajaxSettings,target);},ajaxPrefilter:addToPrefiltersOrTransports(prefilters),ajaxTransport:addToPrefiltersOrTransports(transports),ajax:function(url,options){if(typeof url==="object"){options=url;url=undefined;}
+options=options||{};var transport,cacheURL,responseHeadersString,responseHeaders,timeoutTimer,parts,fireGlobals,i,s=jQuery.ajaxSetup({},options),callbackContext=s.context||s,globalEventContext=s.context&&(callbackContext.nodeType||callbackContext.jquery)?jQuery(callbackContext):jQuery.event,deferred=jQuery.Deferred(),completeDeferred=jQuery.Callbacks("once memory"),statusCode=s.statusCode||{},requestHeaders={},requestHeadersNames={},state=0,strAbort="canceled",jqXHR={readyState:0,getResponseHeader:function(key){var match;if(state===2){if(!responseHeaders){responseHeaders={};while(match=rheaders.exec(responseHeadersString)){responseHeaders[match[1].toLowerCase()]=match[2];}}
+match=responseHeaders[key.toLowerCase()];}
+return match==null?null:match;},getAllResponseHeaders:function(){return state===2?responseHeadersString:null;},setRequestHeader:function(name,value){var lname=name.toLowerCase();if(!state){name=requestHeadersNames[lname]=requestHeadersNames[lname]||name;requestHeaders[name]=value;}
+return this;},overrideMimeType:function(type){if(!state){s.mimeType=type;}
+return this;},statusCode:function(map){var code;if(map){if(state<2){for(code in map){statusCode[code]=[statusCode[code],map[code]];}}else{jqXHR.always(map[jqXHR.status]);}}
+return this;},abort:function(statusText){var finalText=statusText||strAbort;if(transport){transport.abort(finalText);}
+done(0,finalText);return this;}};deferred.promise(jqXHR).complete=completeDeferred.add;jqXHR.success=jqXHR.done;jqXHR.error=jqXHR.fail;s.url=((url||s.url||ajaxLocation)+"").replace(rhash,"").replace(rprotocol,ajaxLocParts[1]+"//");s.type=options.method||options.type||s.method||s.type;s.dataTypes=jQuery.trim(s.dataType||"*").toLowerCase().match(core_rnotwhite)||[""];if(s.crossDomain==null){parts=rurl.exec(s.url.toLowerCase());s.crossDomain=!!(parts&&(parts[1]!==ajaxLocParts[1]||parts[2]!==ajaxLocParts[2]||(parts[3]||(parts[1]==="http:"?"80":"443"))!==(ajaxLocParts[3]||(ajaxLocParts[1]==="http:"?"80":"443"))));}
+if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data,s.traditional);}
+inspectPrefiltersOrTransports(prefilters,s,options,jqXHR);if(state===2){return jqXHR;}
+fireGlobals=s.global;if(fireGlobals&&jQuery.active++===0){jQuery.event.trigger("ajaxStart");}
+s.type=s.type.toUpperCase();s.hasContent=!rnoContent.test(s.type);cacheURL=s.url;if(!s.hasContent){if(s.data){cacheURL=s.url+=(ajax_rquery.test(cacheURL)?"&":"?")+s.data;delete s.data;}
+if(s.cache===false){s.url=rts.test(cacheURL)?cacheURL.replace(rts,"$1_="+ajax_nonce++):cacheURL+(ajax_rquery.test(cacheURL)?"&":"?")+"_="+ajax_nonce++;}}
+if(s.ifModified){if(jQuery.lastModified[cacheURL]){jqXHR.setRequestHeader("If-Modified-Since",jQuery.lastModified[cacheURL]);}
+if(jQuery.etag[cacheURL]){jqXHR.setRequestHeader("If-None-Match",jQuery.etag[cacheURL]);}}
+if(s.data&&s.hasContent&&s.contentType!==false||options.contentType){jqXHR.setRequestHeader("Content-Type",s.contentType);}
+jqXHR.setRequestHeader("Accept",s.dataTypes[0]&&s.accepts[s.dataTypes[0]]?s.accepts[s.dataTypes[0]]+(s.dataTypes[0]!=="*"?", "+allTypes+"; q=0.01":""):s.accepts["*"]);for(i in s.headers){jqXHR.setRequestHeader(i,s.headers[i]);}
+if(s.beforeSend&&(s.beforeSend.call(callbackContext,jqXHR,s)===false||state===2)){return jqXHR.abort();}
+strAbort="abort";for(i in{success:1,error:1,complete:1}){jqXHR[i](s[i]);}
+transport=inspectPrefiltersOrTransports(transports,s,options,jqXHR);if(!transport){done(-1,"No Transport");}else{jqXHR.readyState=1;if(fireGlobals){globalEventContext.trigger("ajaxSend",[jqXHR,s]);}
+if(s.async&&s.timeout>0){timeoutTimer=setTimeout(function(){jqXHR.abort("timeout");},s.timeout);}
+try{state=1;transport.send(requestHeaders,done);}catch(e$2){if(state<2){done(-1,e$2);}else{throw e$2;}}}
+function done(status,nativeStatusText,responses,headers){var isSuccess,success,error,response,modified,statusText=nativeStatusText;if(state===2){return;}
+state=2;if(timeoutTimer){clearTimeout(timeoutTimer);}
+transport=undefined;responseHeadersString=headers||"";jqXHR.readyState=status>0?4:0;isSuccess=status>=200&&status<300||status===304;if(responses){response=ajaxHandleResponses(s,jqXHR,responses);}
+response=ajaxConvert(s,response,jqXHR,isSuccess);if(isSuccess){if(s.ifModified){modified=jqXHR.getResponseHeader("Last-Modified");if(modified){jQuery.lastModified[cacheURL]=modified;}
+modified=jqXHR.getResponseHeader("etag");if(modified){jQuery.etag[cacheURL]=modified;}}
+if(status===204||s.type==="HEAD"){statusText="nocontent";}else{if(status===304){statusText="notmodified";}else{statusText=response.state;success=response.data;error=response.error;isSuccess=!error;}}}else{error=statusText;if(status||!statusText){statusText="error";if(status<0){status=0;}}}
+jqXHR.status=status;jqXHR.statusText=(nativeStatusText||statusText)+"";if(isSuccess){deferred.resolveWith(callbackContext,[success,statusText,jqXHR]);}else{deferred.rejectWith(callbackContext,[jqXHR,statusText,error]);}
+jqXHR.statusCode(statusCode);statusCode=undefined;if(fireGlobals){globalEventContext.trigger(isSuccess?"ajaxSuccess":"ajaxError",[jqXHR,s,isSuccess?success:error]);}
+completeDeferred.fireWith(callbackContext,[jqXHR,statusText]);if(fireGlobals){globalEventContext.trigger("ajaxComplete",[jqXHR,s]);if(!--jQuery.active){jQuery.event.trigger("ajaxStop");}}}
+return jqXHR;},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json");},getScript:function(url,callback){return jQuery.get(url,undefined,callback,"script");}});jQuery.each(["get","post"],function(i,method){jQuery[method]=function(url,data,callback,type){if(jQuery.isFunction(data)){type=type||callback;callback=data;data=undefined;}
+return jQuery.ajax({url:url,type:method,dataType:type,data:data,success:callback});};});function ajaxHandleResponses(s,jqXHR,responses){var ct,type,finalDataType,firstDataType,contents=s.contents,dataTypes=s.dataTypes;while(dataTypes[0]==="*"){dataTypes.shift();if(ct===undefined){ct=s.mimeType||jqXHR.getResponseHeader("Content-Type");}}
+if(ct){for(type in contents){if(contents[type]&&contents[type].test(ct)){dataTypes.unshift(type);break;}}}
+if(dataTypes[0]in responses){finalDataType=dataTypes[0];}else{for(type in responses){if(!dataTypes[0]||s.converters[type+" "+dataTypes[0]]){finalDataType=type;break;}
+if(!firstDataType){firstDataType=type;}}
+finalDataType=finalDataType||firstDataType;}
+if(finalDataType){if(finalDataType!==dataTypes[0]){dataTypes.unshift(finalDataType);}
+return responses[finalDataType];}}
+function ajaxConvert(s,response,jqXHR,isSuccess){var conv2,current,conv,tmp,prev,converters={},dataTypes=s.dataTypes.slice();if(dataTypes[1]){for(conv in s.converters){converters[conv.toLowerCase()]=s.converters[conv];}}
+current=dataTypes.shift();while(current){if(s.responseFields[current]){jqXHR[s.responseFields[current]]=response;}
+if(!prev&&isSuccess&&s.dataFilter){response=s.dataFilter(response,s.dataType);}
+prev=current;current=dataTypes.shift();if(current){if(current==="*"){current=prev;}else{if(prev!=="*"&&prev!==current){conv=converters[prev+" "+current]||converters["* "+current];if(!conv){for(conv2 in converters){tmp=conv2.split(" ");if(tmp[1]===current){conv=converters[prev+" "+tmp[0]]||converters["* "+tmp[0]];if(conv){if(conv===true){conv=converters[conv2];}else{if(converters[conv2]!==true){current=tmp[0];dataTypes.unshift(tmp[1]);}}
+break;}}}}
+if(conv!==true){if(conv&&s["throws"]){response=conv(response);}else{try{response=conv(response);}catch(e$3){return{state:"parsererror",error:conv?e$3:"No conversion from "+prev+" to "+current};}}}}}}}
+return{state:"success",data:response};}
+jQuery.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(text){jQuery.globalEval(text);return text;}}});jQuery.ajaxPrefilter("script",function(s){if(s.cache===undefined){s.cache=false;}
+if(s.crossDomain){s.type="GET";}});jQuery.ajaxTransport("script",function(s){if(s.crossDomain){var script,callback;return{send:function(_,complete){script=jQuery("<script>").prop({async:true,charset:s.scriptCharset,src:s.url}).on("load error",callback=function(evt){script.remove();callback=null;if(evt){complete(evt.type==="error"?404:200,evt.type);}});document.head.appendChild(script[0]);},abort:function(){if(callback){callback();}}};}});var oldCallbacks=[],rjsonp=/(=)\?(?=&|$)|\?\?/;jQuery.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var callback=oldCallbacks.pop()||jQuery.expando+"_"+ajax_nonce++;this[callback]=true;return callback;}});jQuery.ajaxPrefilter("json jsonp",function(s,originalSettings,jqXHR){var callbackName,overwritten,responseContainer,jsonProp=s.jsonp!==false&&(rjsonp.test(s.url)?"url":typeof s.data==="string"&&!(s.contentType||"").indexOf("application/x-www-form-urlencoded")&&rjsonp.test(s.data)&&"data");if(jsonProp||s.dataTypes[0]==="jsonp"){callbackName=s.jsonpCallback=jQuery.isFunction(s.jsonpCallback)?s.jsonpCallback():s.jsonpCallback;if(jsonProp){s[jsonProp]=s[jsonProp].replace(rjsonp,"$1"+callbackName);}else{if(s.jsonp!==false){s.url+=(ajax_rquery.test(s.url)?"&":"?")+s.jsonp+"="+callbackName;}}
+s.converters["script json"]=function(){if(!responseContainer){jQuery.error(callbackName+" was not called");}
+return responseContainer[0];};s.dataTypes[0]="json";overwritten=window[callbackName];window[callbackName]=function(){responseContainer=arguments;};jqXHR.always(function(){window[callbackName]=overwritten;if(s[callbackName]){s.jsonpCallback=originalSettings.jsonpCallback;oldCallbacks.push(callbackName);}
+if(responseContainer&&jQuery.isFunction(overwritten)){overwritten(responseContainer[0]);}
+responseContainer=overwritten=undefined;});return"script";}});jQuery.ajaxSettings.xhr=function(){try{return new XMLHttpRequest;}catch(e$4){}};var xhrSupported=jQuery.ajaxSettings.xhr(),xhrSuccessStatus={0:200,1223:204},xhrId=0,xhrCallbacks={};if(window.ActiveXObject){jQuery(window).on("unload",function(){for(var key in xhrCallbacks){xhrCallbacks[key]();}
+xhrCallbacks=undefined;});}
+jQuery.support.cors=!!xhrSupported&&"withCredentials"in xhrSupported;jQuery.support.ajax=xhrSupported=!!xhrSupported;jQuery.ajaxTransport(function(options){var callback;if(jQuery.support.cors||xhrSupported&&!options.crossDomain){return{send:function(headers,complete){var i,id,xhr=options.xhr();xhr.open(options.type,options.url,options.async,options.username,options.password);if(options.xhrFields){for(i in options.xhrFields){xhr[i]=options.xhrFields[i];}}
+if(options.mimeType&&xhr.overrideMimeType){xhr.overrideMimeType(options.mimeType);}
+if(!options.crossDomain&&!headers["X-Requested-With"]){headers["X-Requested-With"]="XMLHttpRequest";}
+for(i in headers){xhr.setRequestHeader(i,headers[i]);}
+callback=function(type){return function(){if(callback){delete xhrCallbacks[id];callback=xhr.onload=xhr.onerror=null;if(type==="abort"){xhr.abort();}else{if(type==="error"){complete(xhr.status||404,xhr.statusText);}else{complete(xhrSuccessStatus[xhr.status]||xhr.status,xhr.statusText,typeof xhr.responseText==="string"?{text:xhr.responseText}:undefined,xhr.getAllResponseHeaders());}}}};};xhr.onload=callback();xhr.onerror=callback("error");callback=xhrCallbacks[id=xhrId++]=callback("abort");xhr.send(options.hasContent&&options.data||null);},abort:function(){if(callback){callback();}}};}});var fxNow,timerId,rfxtypes=/^(?:toggle|show|hide)$/,rfxnum=new RegExp("^(?:([+-])=|)("+core_pnum+")([a-z%]*)$","i"),rrun=/queueHooks$/,animationPrefilters=[defaultPrefilter],tweeners={"*":[function(prop,value){var tween=this.createTween(prop,value),target=tween.cur(),parts=rfxnum.exec(value),unit=parts&&parts[3]||(jQuery.cssNumber[prop]?"":"px"),start=(jQuery.cssNumber[prop]||unit!=="px"&&+target)&&rfxnum.exec(jQuery.css(tween.elem,prop)),scale=1,maxIterations=20;if(start&&start[3]!==unit){unit=unit||start[3];parts=parts||[];start=+target||1;do{scale=scale||".5";start=start / scale;jQuery.style(tween.elem,prop,start+unit);}while(scale!==(scale=tween.cur()/ target)&&scale!==1&&--maxIterations);}
+if(parts){start=tween.start=+start||+target||0;tween.unit=unit;tween.end=parts[1]?start+(parts[1]+1)*parts[2]:+parts[2];}
+return tween;}]};function createFxNow(){setTimeout(function(){fxNow=undefined;});return fxNow=jQuery.now();}
+function createTween(value,prop,animation){var tween,collection=(tweeners[prop]||[]).concat(tweeners["*"]),index=0,length=collection.length;for(;index<length;index++){if(tween=collection[index].call(animation,prop,value)){return tween;}}}
+function Animation(elem,properties,options){var result,stopped,index=0,length=animationPrefilters.length,deferred=jQuery.Deferred().always(function(){delete tick.elem;}),tick=function(){if(stopped){return false;}
+var currentTime=fxNow||createFxNow(),remaining=Math.max(0,animation.startTime+animation.duration-currentTime),temp=remaining / animation.duration||0,percent=1-temp,index=0,length=animation.tweens.length;for(;index<length;index++){animation.tweens[index].run(percent);}
+deferred.notifyWith(elem,[animation,percent,remaining]);if(percent<1&&length){return remaining;}else{deferred.resolveWith(elem,[animation]);return false;}},animation=deferred.promise({elem:elem,props:jQuery.extend({},properties),opts:jQuery.extend(true,{specialEasing:{}},options),originalProperties:properties,originalOptions:options,startTime:fxNow||createFxNow(),duration:options.duration,tweens:[],createTween:function(prop,end){var tween=jQuery.Tween(elem,animation.opts,prop,end,animation.opts.specialEasing[prop]||animation.opts.easing);animation.tweens.push(tween);return tween;},stop:function(gotoEnd){var index=0,length=gotoEnd?animation.tweens.length:0;if(stopped){return this;}
+stopped=true;for(;index<length;index++){animation.tweens[index].run(1);}
+if(gotoEnd){deferred.resolveWith(elem,[animation,gotoEnd]);}else{deferred.rejectWith(elem,[animation,gotoEnd]);}
+return this;}}),props=animation.props;propFilter(props,animation.opts.specialEasing);for(;index<length;index++){result=animationPrefilters[index].call(animation,elem,props,animation.opts);if(result){return result;}}
+jQuery.map(props,createTween,animation);if(jQuery.isFunction(animation.opts.start)){animation.opts.start.call(elem,animation);}
+jQuery.fx.timer(jQuery.extend(tick,{elem:elem,anim:animation,queue:animation.opts.queue}));return animation.progress(animation.opts.progress).done(animation.opts.done,animation.opts.complete).fail(animation.opts.fail).always(animation.opts.always);}
+function propFilter(props,specialEasing){var index,name,easing,value,hooks;for(index in props){name=jQuery.camelCase(index);easing=specialEasing[name];value=props[index];if(jQuery.isArray(value)){easing=value[1];value=props[index]=value[0];}
+if(index!==name){props[name]=value;delete props[index];}
+hooks=jQuery.cssHooks[name];if(hooks&&"expand"in hooks){value=hooks.expand(value);delete props[name];for(index in value){if(!(index in props)){props[index]=value[index];specialEasing[index]=easing;}}}else{specialEasing[name]=easing;}}}
+jQuery.Animation=jQuery.extend(Animation,{tweener:function(props,callback){if(jQuery.isFunction(props)){callback=props;props=["*"];}else{props=props.split(" ");}
+var prop,index=0,length=props.length;for(;index<length;index++){prop=props[index];tweeners[prop]=tweeners[prop]||[];tweeners[prop].unshift(callback);}},prefilter:function(callback,prepend){if(prepend){animationPrefilters.unshift(callback);}else{animationPrefilters.push(callback);}}});function defaultPrefilter(elem,props,opts){var prop,value,toggle,tween,hooks,oldfire,anim=this,orig={},style=elem.style,hidden=elem.nodeType&&isHidden(elem),dataShow=data_priv.get(elem,"fxshow");if(!opts.queue){hooks=jQuery._queueHooks(elem,"fx");if(hooks.unqueued==null){hooks.unqueued=0;oldfire=hooks.empty.fire;hooks.empty.fire=function(){if(!hooks.unqueued){oldfire();}};}
+hooks.unqueued++;anim.always(function(){anim.always(function(){hooks.unqueued--;if(!jQuery.queue(elem,"fx").length){hooks.empty.fire();}});});}
+if(elem.nodeType===1&&("height"in props||"width"in props)){opts.overflow=[style.overflow,style.overflowX,style.overflowY];if(jQuery.css(elem,"display")==="inline"&&jQuery.css(elem,"float")==="none"){style.display="inline-block";}}
+if(opts.overflow){style.overflow="hidden";anim.always(function(){style.overflow=opts.overflow[0];style.overflowX=opts.overflow[1];style.overflowY=opts.overflow[2];});}
+for(prop in props){value=props[prop];if(rfxtypes.exec(value)){delete props[prop];toggle=toggle||value==="toggle";if(value===(hidden?"hide":"show")){if(value==="show"&&dataShow&&dataShow[prop]!==undefined){hidden=true;}else{continue;}}
+orig[prop]=dataShow&&dataShow[prop]||jQuery.style(elem,prop);}}
+if(!jQuery.isEmptyObject(orig)){if(dataShow){if("hidden"in dataShow){hidden=dataShow.hidden;}}else{dataShow=data_priv.access(elem,"fxshow",{});}
+if(toggle){dataShow.hidden=!hidden;}
+if(hidden){jQuery(elem).show();}else{anim.done(function(){jQuery(elem).hide();});}
+anim.done(function(){var prop;data_priv.remove(elem,"fxshow");for(prop in orig){jQuery.style(elem,prop,orig[prop]);}});for(prop in orig){tween=createTween(hidden?dataShow[prop]:0,prop,anim);if(!(prop in dataShow)){dataShow[prop]=tween.start;if(hidden){tween.end=tween.start;tween.start=prop==="width"||prop==="height"?1:0;}}}}}
+function Tween(elem,options,prop,end,easing){return new Tween.prototype.init(elem,options,prop,end,easing);}
+jQuery.Tween=Tween;Tween.prototype={constructor:Tween,init:function(elem,options,prop,end,easing,unit){this.elem=elem;this.prop=prop;this.easing=easing||"swing";this.options=options;this.start=this.now=this.cur();this.end=end;this.unit=unit||(jQuery.cssNumber[prop]?"":"px");},cur:function(){var hooks=Tween.propHooks[this.prop];return hooks&&hooks.get?hooks.get(this):Tween.propHooks._default.get(this);},run:function(percent){var eased,hooks=Tween.propHooks[this.prop];if(this.options.duration){this.pos=eased=jQuery.easing[this.easing](percent,this.options.duration*percent,0,1,this.options.duration);}else{this.pos=eased=percent;}
+this.now=(this.end-this.start)*eased+this.start;if(this.options.step){this.options.step.call(this.elem,this.now,this);}
+if(hooks&&hooks.set){hooks.set(this);}else{Tween.propHooks._default.set(this);}
+return this;}};Tween.prototype.init.prototype=Tween.prototype;Tween.propHooks={_default:{get:function(tween){var result;if(tween.elem[tween.prop]!=null&&(!tween.elem.style||tween.elem.style[tween.prop]==null)){return tween.elem[tween.prop];}
+result=jQuery.css(tween.elem,tween.prop,"");return!result||result==="auto"?0:result;},set:function(tween){if(jQuery.fx.step[tween.prop]){jQuery.fx.step[tween.prop](tween);}else{if(tween.elem.style&&(tween.elem.style[jQuery.cssProps[tween.prop]]!=null||jQuery.cssHooks[tween.prop])){jQuery.style(tween.elem,tween.prop,tween.now+tween.unit);}else{tween.elem[tween.prop]=tween.now;}}}}};Tween.propHooks.scrollTop=Tween.propHooks.scrollLeft={set:function(tween){if(tween.elem.nodeType&&tween.elem.parentNode){tween.elem[tween.prop]=tween.now;}}};jQuery.each(["toggle","show","hide"],function(i,name){var cssFn=jQuery.fn[name];jQuery.fn[name]=function(speed,easing,callback){return speed==null||typeof speed==="boolean"?cssFn.apply(this,arguments):this.animate(genFx(name,true),speed,easing,callback);};});jQuery.fn.extend({fadeTo:function(speed,to,easing,callback){return this.filter(isHidden).css("opacity",0).show().end().animate({opacity:to},speed,easing,callback);},animate:function(prop,speed,easing,callback){var empty=jQuery.isEmptyObject(prop),optall=jQuery.speed(speed,easing,callback),doAnimation=function(){var anim=Animation(this,jQuery.extend({},prop),optall);if(empty||data_priv.get(this,"finish")){anim.stop(true);}};doAnimation.finish=doAnimation;return empty||optall.queue===false?this.each(doAnimation):this.queue(optall.queue,doAnimation);},stop:function(type,clearQueue,gotoEnd){var stopQueue=function(hooks){var stop=hooks.stop;delete hooks.stop;stop(gotoEnd);};if(typeof type!=="string"){gotoEnd=clearQueue;clearQueue=type;type=undefined;}
+if(clearQueue&&type!==false){this.queue(type||"fx",[]);}
+return this.each(function(){var dequeue=true,index=type!=null&&type+"queueHooks",timers=jQuery.timers,data=data_priv.get(this);if(index){if(data[index]&&data[index].stop){stopQueue(data[index]);}}else{for(index in data){if(data[index]&&data[index].stop&&rrun.test(index)){stopQueue(data[index]);}}}
+for(index=timers.length;index--;){if(timers[index].elem===this&&(type==null||timers[index].queue===type)){timers[index].anim.stop(gotoEnd);dequeue=false;timers.splice(index,1);}}
+if(dequeue||!gotoEnd){jQuery.dequeue(this,type);}});},finish:function(type){if(type!==false){type=type||"fx";}
+return this.each(function(){var index,data=data_priv.get(this),queue=data[type+"queue"],hooks=data[type+"queueHooks"],timers=jQuery.timers,length=queue?queue.length:0;data.finish=true;jQuery.queue(this,type,[]);if(hooks&&hooks.stop){hooks.stop.call(this,true);}
+for(index=timers.length;index--;){if(timers[index].elem===this&&timers[index].queue===type){timers[index].anim.stop(true);timers.splice(index,1);}}
+for(index=0;index<length;index++){if(queue[index]&&queue[index].finish){queue[index].finish.call(this);}}
+delete data.finish;});}});function genFx(type,includeWidth){var which,attrs={height:type},i=0;includeWidth=includeWidth?1:0;for(;i<4;i+=2-includeWidth){which=cssExpand[i];attrs["margin"+which]=attrs["padding"+which]=type;}
+if(includeWidth){attrs.opacity=attrs.width=type;}
+return attrs;}
+jQuery.each({slideDown:genFx("show"),slideUp:genFx("hide"),slideToggle:genFx("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(name,props){jQuery.fn[name]=function(speed,easing,callback){return this.animate(props,speed,easing,callback);};});jQuery.speed=function(speed,easing,fn){var opt=speed&&typeof speed==="object"?jQuery.extend({},speed):{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:opt.duration in jQuery.fx.speeds?jQuery.fx.speeds[opt.duration]:jQuery.fx.speeds._default;if(opt.queue==null||opt.queue===true){opt.queue="fx";}
+opt.old=opt.complete;opt.complete=function(){if(jQuery.isFunction(opt.old)){opt.old.call(this);}
+if(opt.queue){jQuery.dequeue(this,opt.queue);}};return opt;};jQuery.easing={linear:function(p){return p;},swing:function(p){return.5-Math.cos(p*Math.PI)/ 2;}};jQuery.timers=[];jQuery.fx=Tween.prototype.init;jQuery.fx.tick=function(){var timer,timers=jQuery.timers,i=0;fxNow=jQuery.now();for(;i<timers.length;i++){timer=timers[i];if(!timer()&&timers[i]===timer){timers.splice(i--,1);}}
+if(!timers.length){jQuery.fx.stop();}
+fxNow=undefined;};jQuery.fx.timer=function(timer){if(timer()&&jQuery.timers.push(timer)){jQuery.fx.start();}};jQuery.fx.interval=13;jQuery.fx.start=function(){if(!timerId){timerId=setInterval(jQuery.fx.tick,jQuery.fx.interval);}};jQuery.fx.stop=function(){clearInterval(timerId);timerId=null;};jQuery.fx.speeds={slow:600,fast:200,_default:400};jQuery.fx.step={};if(jQuery.expr&&jQuery.expr.filters){jQuery.expr.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem;}).length;};}
+jQuery.fn.offset=function(options){if(arguments.length){return options===undefined?this:this.each(function(i){jQuery.offset.setOffset(this,options,i);});}
+var docElem,win,elem=this[0],box={top:0,left:0},doc=elem&&elem.ownerDocument;if(!doc){return;}
+docElem=doc.documentElement;if(!jQuery.contains(docElem,elem)){return box;}
+if(typeof elem.getBoundingClientRect!==core_strundefined){box=elem.getBoundingClientRect();}
+win=getWindow(doc);return{top:box.top+win.pageYOffset-docElem.clientTop,left:box.left+win.pageXOffset-docElem.clientLeft};};jQuery.offset={setOffset:function(elem,options,i){var curPosition,curLeft,curCSSTop,curTop,curOffset,curCSSLeft,calculatePosition,position=jQuery.css(elem,"position"),curElem=jQuery(elem),props={};if(position==="static"){elem.style.position="relative";}
+curOffset=curElem.offset();curCSSTop=jQuery.css(elem,"top");curCSSLeft=jQuery.css(elem,"left");calculatePosition=(position==="absolute"||position==="fixed")&&(curCSSTop+curCSSLeft).indexOf("auto")>-1;if(calculatePosition){curPosition=curElem.position();curTop=curPosition.top;curLeft=curPosition.left;}else{curTop=parseFloat(curCSSTop)||0;curLeft=parseFloat(curCSSLeft)||0;}
+if(jQuery.isFunction(options)){options=options.call(elem,i,curOffset);}
+if(options.top!=null){props.top=options.top-curOffset.top+curTop;}
+if(options.left!=null){props.left=options.left-curOffset.left+curLeft;}
+if("using"in options){options.using.call(elem,props);}else{curElem.css(props);}}};jQuery.fn.extend({position:function(){if(!this[0]){return;}
+var offsetParent,offset,elem=this[0],parentOffset={top:0,left:0};if(jQuery.css(elem,"position")==="fixed"){offset=elem.getBoundingClientRect();}else{offsetParent=this.offsetParent();offset=this.offset();if(!jQuery.nodeName(offsetParent[0],"html")){parentOffset=offsetParent.offset();}
+parentOffset.top+=jQuery.css(offsetParent[0],"borderTopWidth",true);parentOffset.left+=jQuery.css(offsetParent[0],"borderLeftWidth",true);}
+return{top:offset.top-parentOffset.top-jQuery.css(elem,"marginTop",true),left:offset.left-parentOffset.left-jQuery.css(elem,"marginLeft",true)};},offsetParent:function(){return this.map(function(){var offsetParent=this.offsetParent||docElem;while(offsetParent&&(!jQuery.nodeName(offsetParent,"html")&&jQuery.css(offsetParent,"position")==="static")){offsetParent=offsetParent.offsetParent;}
+return offsetParent||docElem;});}});jQuery.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(method,prop){var top="pageYOffset"===prop;jQuery.fn[method]=function(val){return jQuery.access(this,function(elem,method,val){var win=getWindow(elem);if(val===undefined){return win?win[prop]:elem[method];}
+if(win){win.scrollTo(!top?val:window.pageXOffset,top?val:window.pageYOffset);}else{elem[method]=val;}},method,val,arguments.length,null);};});function getWindow(elem){return jQuery.isWindow(elem)?elem:elem.nodeType===9&&elem.defaultView;}
+jQuery.each({Height:"height",Width:"width"},function(name,type){jQuery.each({padding:"inner"+name,content:type,"":"outer"+name},function(defaultExtra,funcName){jQuery.fn[funcName]=function(margin,value){var chainable=arguments.length&&(defaultExtra||typeof margin!=="boolean"),extra=defaultExtra||(margin===true||value===true?"margin":"border");return jQuery.access(this,function(elem,type,value){var doc;if(jQuery.isWindow(elem)){return elem.document.documentElement["client"+name];}
+if(elem.nodeType===9){doc=elem.documentElement;return Math.max(elem.body["scroll"+name],doc["scroll"+name],elem.body["offset"+name],doc["offset"+name],doc["client"+name]);}
+return value===undefined?jQuery.css(elem,type,extra):jQuery.style(elem,type,value,extra);},type,chainable?margin:undefined,chainable,null);};});});jQuery.fn.size=function(){return this.length;};jQuery.fn.andSelf=jQuery.fn.addBack;if(typeof module==="object"&&module&&typeof module.exports==="object"){module.exports=jQuery;}else{if(typeof define==="function"&&define.amd){define("jquery",[],function(){return jQuery;});}}
+if(typeof window==="object"&&typeof window.document==="object"){window.jQuery=window.$=jQuery;}})(window);
diff --git a/static/js/manage.js b/static/js/manage.js
new file mode 100644
index 0000000..10898d0
--- /dev/null
+++ b/static/js/manage.js
@@ -0,0 +1,22 @@
+function addtime(e) {
+ e.preventDefault();
+ document.getElementById("seconds").value = this.dataset.secs;
+}
+
+function pvw(e) {
+ prev = document.getElementById("prev_desc");
+ prev.innerHTML = desc.value;
+ prev.style.display = "block";
+ prev.addEventListener("input", function() { desc.value = prev.innerHTML; });
+}
+
+document.addEventListener("DOMContentLoaded", function(e) {
+ var list = document.getElementById("timelist");
+ if (list) {
+ var secs = document.getElementById("timelist").getElementsByTagName("a");
+ for(var i=0;i<secs.length;i++) secs[i].addEventListener("click", addtime);
+ }
+
+ desc = document.getElementById("brd_desc");
+ if (desc) desc.addEventListener("input", pvw);
+}); \ No newline at end of file
diff --git a/static/js/mobile.js b/static/js/mobile.js
new file mode 100644
index 0000000..b4dd8cf
--- /dev/null
+++ b/static/js/mobile.js
@@ -0,0 +1,447 @@
+function sendPost(e) {
+ e.preventDefault();
+ var button = document.getElementById("post");
+ button.disabled = true;
+ var sendpost = new XMLHttpRequest();
+ var postform = document.getElementById("postform");
+ sendpost.open("POST", "/cgi/api/post", true);
+ sendpost.send(new FormData(postform));
+ sendpost.onreadystatechange = function() {
+ if (sendpost.readyState == 4) {
+ button.disabled = false;
+ var response = JSON.parse(sendpost.responseText);
+ if (response.state == "success") { postform.message.value = ""; checkNew(e); }
+ else alert(response.message);
+ }
+ }
+}
+
+function postClick(e) {
+ e.preventDefault();
+ var sel = window.getSelection().toString();
+ if (sel) { sel=sel.replace(/^/gm, ">")+"\n"; sel="\n"+sel; }
+ insert(">>" + parseInt(this.innerHTML, 10) + sel);
+}
+
+function insert(text) {
+ var textarea=document.forms.postform.message;
+ if(textarea) {
+ if(textarea.createTextRange && textarea.caretPos) { // IE
+ var caretPos=textarea.caretPos;
+ caretPos.text=caretPos.text.charAt(caretPos.text.length-1)==" "?text+" ":text;
+ } else if(textarea.setSelectionRange) { // Firefox
+ var start=textarea.selectionStart;
+ var end=textarea.selectionEnd;
+ textarea.value=textarea.value.substr(0,start)+text+textarea.value.substr(end);
+ textarea.setSelectionRange(start+text.length,start+text.length);
+ } else {
+ textarea.value+=text+" ";
+ }
+ textarea.focus();
+ }
+ return false;
+}
+
+function getPassword() {
+ if (weabot.password) return weabot.password;
+ var char="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ var pass="";
+ for (var i=0;i<8;i++) {
+ var rnd = Math.floor(Math.random()*char.length);
+ pass += char.substring(rnd, rnd+1);
+ }
+ console.log(weabot.password);
+ weabot.password = pass;
+ localStorage.setItem("weabot", JSON.stringify(weabot));
+ return(pass);
+}
+
+function saveInputs(e) {
+ var e = e || window.event;
+ var form = e.target || e.srcElement;
+ if(typeof(form.fielda) !== "undefined") weabot.name = form.fielda.value;
+ if(typeof(form.fielda) !== "undefined") weabot.email = form.fieldb.value;
+ localStorage.setItem("weabot", JSON.stringify(weabot));
+}
+
+function setInputs() {
+ with(document.getElementById("postform")) {
+ if(typeof(fielda) !== 'undefined' && !fielda.value && weabot.name) fielda.value = weabot.name;
+ if(typeof(fielda) !== 'undefined' && !fieldb.value && weabot.email) fieldb.value = weabot.email;
+ if(!password.value) password.value = getPassword();
+ addEventListener("submit", saveInputs);
+ }
+}
+
+function showMenu(e) {
+ e.preventDefault();
+ if (document.getElementById("mnu-opened")) closeMenu(e);
+ this.id = "mnu-opened";
+ var brd = postform.board.value;
+ var post = this.parentNode.parentNode;
+ if (document.body.className === "txt") {
+ var id = post.id.substr(1);
+ var num = parseInt(post.getElementsByClassName("num")[0].innerText, 10);
+ } else {
+ var id = post.getElementsByClassName("num")[0].innerText;
+ var num = ((post.className === "first") ? 1 : 0);
+ }
+ var menu = document.createElement("div");
+ menu.id = "mnu-list";
+ menu.style.top = (e.pageY + 5) + "px";
+ menu.style.left = (e.pageX + 5) + "px";
+ document.body.appendChild(menu);
+ menu = document.getElementById("mnu-list");
+ var rep = document.createElement("a");
+ rep.href = "#";
+ rep.innerText = "Denunciar post";
+ rep.addEventListener("click", function(e) {
+ var reason = prompt("Razón de denuncia:");
+ if (reason === "") while(reason === "") reason = prompt("Error: Ingresa una razón.");
+ if (reason) {
+ var rep_req = new XMLHttpRequest();
+ var report = "/cgi/report/" + brd + "/" + id + ((num) ? "/" + num : "") + "?reason=" + reason;
+ rep_req.open("GET", report, true);
+ rep_req.send();
+ rep_req.onreadystatechange = function() {
+ if (rep_req.readyState == 4 && rep_req.status == 200) alert("Denuncia enviada.");
+ }
+ }
+ });
+ menu.appendChild(rep);
+ var del = document.createElement("a");
+ del.href = "#";
+ del.innerText = "Eliminar post";
+ del.addEventListener("click", function(e) {
+ if(confirm("¿Seguro que deseas borrar el mensaje "+((num) ? num : id)+"?")) {
+ var del_req = new XMLHttpRequest();
+ var del_form = "/cgi/api/delete?dir=" + brd + "&id=" + id + "&password=" + postform.password.value;
+ del_req.open("GET", del_form, true);
+ del_req.send();
+ del_req.onreadystatechange = function() {
+ if (del_req.readyState == 4) {
+ var response = JSON.parse(del_req.responseText);
+ if (response.state == "success") {
+ if (num == 1) {
+ alert("Hilo eliminado.");
+ document.location = "/cgi/mobile/" + brd;
+ } else {
+ alert("Mensaje eliminado.");
+ location.reload();
+ }
+ } else if (response.state == "failed") alert(response.message);
+ }
+ }
+ }
+ });
+ menu.appendChild(del);
+ var file = post.getElementsByClassName("thm")[0];
+ if (file) {
+ var dfile = document.createElement("a");
+ dfile.href = "#";
+ dfile.innerText = "Eliminar archivo";
+ dfile.addEventListener("click", function(e) {
+ if(confirm("¿Seguro que deseas borrar el archivo del mensaje "+((num) ? num : id)+"?")) {
+ var fdel_req = new XMLHttpRequest();
+ var fdel_form = "/cgi/api/delete?dir=" + brd + "&id=" + id + "&password=" + postform.password.value + "&imageonly=true";
+ fdel_req.open("GET", fdel_form, true);
+ fdel_req.send();
+ fdel_req.onreadystatechange = function() {
+ if (fdel_req.readyState == 4) {
+ var response = JSON.parse(fdel_req.responseText);
+ if (response.state == "success") {
+ alert("Archivo eliminado.");
+ post.removeChild(file);
+ } else if (response.state == "failed") alert(response.message);
+ }
+ }
+ }
+ });
+ menu.appendChild(dfile);
+ }
+ e.stopPropagation();
+ this.removeEventListener("click", showMenu);
+ document.addEventListener("click", closeMenu);
+}
+
+function closeMenu(e) {
+ var menu = document.getElementById("mnu-list");
+ menu.parentElement.removeChild(menu);
+ document.removeEventListener("click", closeMenu);
+ var btn = document.getElementById("mnu-opened");
+ btn.addEventListener("click", showMenu);
+ btn.removeAttribute("id");
+ e.preventDefault();
+}
+
+function searchSubjects() {
+ var filter = document.getElementById("search").value.toLowerCase();
+ var nodes = document.getElementsByClassName("list")[0].getElementsByTagName("a");
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].innerHTML.toLowerCase().split(/<\/?br[^>]*>\s*/im)[0].includes(filter))
+ nodes[i].removeAttribute("style");
+ else nodes[i].style.display = "none";
+ }
+}
+
+function searchCatalog() {
+ var filter = document.getElementById("catsearch").value.toLowerCase();
+ var nodes = document.getElementsByClassName("cat");
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].innerText.toLowerCase().substring(nodes[i].innerText.indexOf("R)")+2).includes(filter))
+ nodes[i].removeAttribute("style");
+ else nodes[i].style.display = "none";
+ }
+}
+
+var lastTime = 0;
+var refreshInterval;
+var refreshMaxTime = 30;
+var refreshTime;
+var manual = 0;
+var serviceType = 0;
+var thread_length = 0;
+var thread_lastreply = 0;
+var thread_title = "";
+var thread_first_length = 0;
+var http_request = new XMLHttpRequest();
+
+function checkNew(e) {
+ e.preventDefault();
+ manual = 1;
+ loadJSON();
+ if (chk.checked) refreshMaxTime = 25;
+}
+
+function loadJSON() {
+ if (chk.checked) stopCounter("...");
+ if (manual) {
+ document.getElementById("n").style.color = "gray";
+ document.getElementById("n").innerText = "Revisando...";
+ }
+ var data_file;
+ if (serviceType)
+ data_file = "/cgi/api/thread?dir=" + postform.board.value + "&id=" + postform.parent.value + "&offset=" + thread_length + "&time=" + lastTime;
+ else return false;
+ http_request.open("GET", data_file, true);
+ http_request.send();
+}
+
+function updateThread(posts, total_replies, serverTime) {
+ thread_div = document.getElementById("thread");
+ last_elem = document.getElementById("n");
+
+ for (var i = 0; i < posts.length; i++) {
+ post = posts[i];
+ brd = postform.board.value;
+ var div = document.createElement('div');
+ div.className = "pst";
+ div.id = "p" + post.id;
+ if (post.IS_DELETED == 0) {
+ s_name = post.name;
+ if (post.tripcode) s_name += ' ' + post.tripcode;
+ s_time = post.timestamp_formatted.replace(/\(.{1,3}\)/g, " ");
+ if (post.file)
+ s_img = '<a href="/' + brd + '/src/' + post.file + '" target="_blank" class="thm"><img src="/' + brd + '/mobile/' + post.thumb + '" /><br />' + Math.round(post.file_size/1024) + 'KB ' + post.file.substring(post.file.lastIndexOf(".")+1, post.file.length).toUpperCase() + '</a>';
+ else s_img = '';
+ }
+ if (serviceType == 1) {
+ var pad = "0000" + (thread_length + i + 1);
+ pad = pad.substr(pad.length-4);
+ if (post.IS_DELETED == 0)
+ div.innerHTML = '<h3><a href="#" class="num">' + pad + '</a> ' + s_name + '</h3>' + s_img + '<div class="msg">' + post.message + '</div><h4>' + s_time + '<a href="#" class="mnu">|||</a></h4>';
+ else if (post.IS_DELETED == 1)
+ div.innerHTML = '<h3 class="del"><a href="#" class="num">' + pad + '</a> : Eliminado por el usuario.</h3>';
+ else
+ div.innerHTML = '<h3 class="del"><a href="#" class="num">' + pad + '</a> : Eliminado por miembro del staff.</h3>';
+ } else {
+ if (post.IS_DELETED == 0) {
+ div.innerHTML = '<h3>' + s_name + ' ' + s_time + ' <a href="#" class="num" name="' + post.id + '">' + post.id + '</a><a href="#" class="mnu">|||</a></h3>' + s_img + '<div class="msg">' + post.message + '</div>';
+ } else if (post.IS_DELETED == 1) { div.innerHTML = '<h3 class="del"><a name="' + post.id + '"></a>No.' + post.id + ' eliminado por el usuario.</h3>'; }
+ else { div.innerHTML = '<h3 class="del"><a name="' + post.id + '"></a>No.' + post.id + ' eliminado por miembro del staff.</h3>'; }
+ }
+
+ div.getElementsByClassName("mnu")[0].addEventListener("click", showMenu);
+ div.getElementsByClassName("num")[0].addEventListener("click", postClick);
+ thread_div.insertBefore(div, last_elem);
+ document.getElementsByTagName("h1")[0].getElementsByTagName("span")[0].innerText = "(" + (thread_length + i + 1) + ")"
+ }
+
+ if (posts.length > 0) {
+ if (!manual) refreshMaxTime = 10;
+ if (!document.hasFocus())
+ if (posts.length > 1) notif(thread_title, posts.length + ' nuevos mensajes');
+ else notif(thread_title, 'Un nuevo mensaje');
+ } else { if (refreshMaxTime <= 60) refreshMaxTime += 5; }
+
+ thread_length = parseInt(total_replies) + 1;
+ new_unread = thread_length - thread_first_length;
+
+ if (new_unread) document.title = '(' + new_unread + ') ' + thread_title;
+ else document.title = thread_title;
+}
+
+function notif(title, msg) {
+ var n = new Notification(title, { body: msg });
+ setTimeout(n.close.bind(n), 10000);
+}
+
+function counter() {
+ if (refreshTime < 1) loadJSON();
+ else {
+ refreshTime--;
+ document.getElementById("counter").innerHTML = (refreshTime + 1);
+ }
+}
+
+function detectService() {
+ if (document.getElementById("thread")) {
+ thread_title = document.getElementsByTagName("h1")[0].innerHTML.split(" \<span\>")[0] + " - " + document.title;
+ thread_length = parseInt(document.getElementsByTagName("h1")[0].getElementsByTagName("span")[0].innerText.slice(1, -1), 10);
+ thread_first_length = thread_length;
+ if (document.body.className === "txt") {
+ serviceType = 1;
+ replylist = document.getElementsByClassName("pst");
+ thread_lastreply = parseInt(replylist[replylist.length - 1].getElementsByClassName("num")[0].innerText);
+ if (thread_length == thread_lastreply) {
+ serviceType = 1;
+ document.getElementById("n2").setAttribute("style", "border-top:1px solid #c6c7c8;border-left:1px solid #c6c7c8;display:inline-block;text-align:center;width:50%;");
+ return true;
+ } else return false;
+ } else if (document.body.className === "img") {
+ serviceType = 2;
+ document.getElementById("n").innerText = "Ver nuevos posts";
+ document.getElementById("n2").setAttribute("style", "border-top:1px solid #333;border-left:1px solid #333;display:inline-block;text-align:center;width:50%;");
+ replylist = document.getElementsByClassName("first");
+ replylist += document.getElementsByClassName("pst");
+ return true;
+ }
+ } else return false;
+}
+
+function startCounter() {
+ refreshTime = refreshMaxTime;
+ counter();
+ refreshInterval = setInterval(counter, 1000);
+}
+
+function stopCounter(str) {
+ clearInterval(refreshInterval);
+ document.getElementById("counter").innerHTML = str;
+}
+
+function autoRefresh(e) {
+ chk_snd = document.getElementById("autosound");
+ if (document.getElementById("autorefresh").checked) {
+ if (chk_snd) chk_snd.disabled = false;
+ Notification.requestPermission();
+ lastTime = Math.floor(Date.now() / 1000);
+ refreshTime = refreshMaxTime;
+ startCounter();
+ } else {
+ if (chk_snd) document.getElementById("autosound").disabled = true;
+ stopCounter("OFF");
+ }
+}
+
+http_request.onreadystatechange = function() {
+ if (http_request.readyState == 4) {
+ var jsonObj = JSON.parse(http_request.responseText);
+ if (jsonObj.state == "success") {
+ updateThread(jsonObj.posts, jsonObj.total_replies, jsonObj.time);
+ lastTime = jsonObj.time;
+ if (chk.checked) startCounter();
+ }
+ if (manual) {
+ document.getElementById("n").style.color = "inherit";
+ document.getElementById("n").innerText = "Ver nuevos posts";
+ }
+ manual = 0;
+ }
+}
+
+function sortList(type) {
+ for(var i=0;i<srts.length;i++) srts[i].removeAttribute("class");
+ srts[type].className = "sel";
+ var cont = document.getElementById("to_sort");
+ var elem = cont.getElementsByTagName("a");
+ var arr = Array.prototype.slice.call(elem);
+ if (type==0) arr.sort(function (a,b) { return (a.dataset.num-b.dataset.num) });
+ else if (type==1) arr.sort(function (a,b) { return (b.dataset.id-a.dataset.id) });
+ else if (type==2) arr.sort(function (a,b) { return (a.dataset.id-b.dataset.id) });
+ else if (type==3) arr.sort(function (a,b) { return (b.dataset.res-a.dataset.res) });
+ else if (type==4) arr.sort(function (a,b) { return (a.dataset.res-b.dataset.res) });
+ for (var j=0;j<arr.length;j++) cont.appendChild(arr[j]);
+}
+
+document.addEventListener("DOMContentLoaded", function(e) {
+ if (localStorage.hasOwnProperty("weabot")) weabot = JSON.parse(localStorage.getItem("weabot"));
+ else weabot = {"name":null,"email":null,"password":null};
+
+ var ids = document.getElementsByClassName("num");
+ for(var i=0;i<ids.length;i++) ids[i].addEventListener("click", postClick);
+
+ var form = document.getElementById("postform");
+ if (form) {
+ setInputs();
+ if (document.getElementById("post").value == "Responder")
+ form.addEventListener("submit", sendPost);
+ }
+
+ if (document.getElementById("search")) document.getElementById("search").addEventListener("keyup", searchSubjects);
+ if (document.getElementById("catsearch")) document.getElementById("catsearch").addEventListener("keyup", searchCatalog);
+ if (document.getElementById("to_sort")) {
+ srts = document.getElementsByClassName("ord")[0].getElementsByTagName("a");
+ for(var i=0;i<srts.length;i++) srts[i].addEventListener("click", function(e) { e.preventDefault(); sortList(this.dataset.sort); });
+ }
+
+ if (document.getElementById("thread")) {
+ var mnu = document.createElement('a');
+ mnu.href = "#";
+ mnu.className = "mnu";
+ mnu.innerHTML = "|||";
+ if (document.body.className === "txt") var ft = document.getElementsByTagName("h4");
+ else if (document.body.className === "img") var ft = document.getElementsByTagName("h3");
+ for(var i=0;i<ft.length;i++) {
+ if (!ft[i].classList.contains("del")) {
+ var cln = mnu.cloneNode(true);
+ cln.addEventListener("click", showMenu);
+ ft[i].appendChild(cln);
+ }
+ }
+ }
+
+ if (!detectService()) return;
+ document.title = thread_title;
+ document.getElementById("n").style.display = "inline-block";
+ document.getElementById("n").style.width = "50%";
+ document.getElementById("n").addEventListener("click", checkNew);
+ var lbl = document.createElement("label");
+ lbl.id = "auto";
+ lbl.style.display = "block";
+ lbl.style.padding = "6px 0";
+ var btn = document.createElement("input");
+ btn.id = "autorefresh";
+ btn.setAttribute("type", "checkbox");
+ btn.addEventListener("click", autoRefresh);
+ var cnt = document.createElement("span");
+ cnt.id = "counter";
+ cnt.textContent = "OFF";
+ document.getElementById("n2").appendChild(lbl);
+ document.getElementById("auto").appendChild(btn);
+ document.getElementById("auto").appendChild(document.createTextNode(" Auto "));
+ document.getElementById("auto").appendChild(cnt);
+
+ chk = document.getElementById("autorefresh");
+ if (localStorage.getItem("autorefreshmobile")) {
+ chk.checked = true;
+ autoRefresh();
+ }
+});
+
+window.addEventListener("unload", function() {
+ chk = document.getElementById("autorefresh");
+ if (!serviceType) return;
+ if (chk.checked) localStorage.setItem("autorefreshmobile", true);
+ else localStorage.removeItem("autorefreshmobile");
+}); \ No newline at end of file
diff --git a/static/js/paintbbs/PaintBBS-1.1.11.css b/static/js/paintbbs/PaintBBS-1.1.11.css
new file mode 100644
index 0000000..776f63d
--- /dev/null
+++ b/static/js/paintbbs/PaintBBS-1.1.11.css
@@ -0,0 +1,535 @@
+.NEO {
+ margin:0;
+ line-height:18px;
+
+ user-select: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+
+ touch-callout: none;
+ -webkit-touch-callout: none;
+}
+
+.NEO *:active,
+.NEO *:hover {
+ cursor: default;
+}
+
+.NEO #container{
+ width: 100%;
+ height: 100%;
+ position: relative;
+ border: 1px dotted transparent;
+}
+
+.NEO #center{
+ display: table;
+ position: relative;
+ height: 100%;
+ margin: auto;
+}
+
+.NEO #toolsWrapper{
+ width: 52px;
+ display: table;
+ position:absolute;
+ top: 0;
+ right: -3px;
+}
+
+.NEO #tools{
+ width: 52px;
+ display: table-cell;
+ vertical-align: middle;
+ position: relative;
+}
+
+.NEO #painterContainer{
+ display:table-cell;
+ vertical-align: middle;
+ position: relative;
+}
+
+.NEO #painterWrapper{
+ padding: 0 55px 0 0;
+ position: relative;
+
+ float:right; /* なぜかChrome55でずれるので対策 */
+}
+
+.NEO #upper {
+ height:30px;
+ padding-right: 20px;
+ text-align:right;
+}
+
+.NEO #lower {
+ height:30px;
+}
+
+.NEO #painter {
+ position: relative;
+ padding: 20px 20px 20px 20px;
+}
+
+.NEO #canvas {
+ position: relative;
+ width: 300px;
+ height: 300px;
+ background-color: white;
+}
+
+.NEO #headerButtons {
+ position: absolute;
+ top: 5px;
+ left: 5px;
+}
+
+.NEO #footerButtons {
+ position: absolute;
+ bottom: 5px;
+ left: 5px;
+}
+
+
+/*
+-----------------------
+ Modal Window
+-----------------------
+*/
+
+.NEO #pageView{
+ background-color: white;
+}
+
+.NEO #windowView{
+ z-index: 9999;
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: white;
+}
+
+/*
+-----------------------
+ Controls
+-----------------------
+*/
+
+.NEO #zoomMinus {
+ padding: 0;
+ margin: 0;
+ width:16px;
+ height:16px;
+ margin-left:1px;
+}
+
+.NEO #zoomPlus {
+ padding: 0;
+ margin: 0;
+ width:16px;
+ height:16px;
+}
+
+.NEO #zoomMinusWrapper {
+ position: absolute;
+ right: -20px;
+ bottom: -21px;
+ width: 19px;
+ height: 19px;
+ text-align:center;
+}
+
+.NEO #zoomPlusWrapper {
+ position: absolute;
+ left: -21px;
+ bottom: -21px;
+ width: 19px;
+ height: 19px;
+ text-overflow: hidden;
+ text-align:center;
+}
+
+.NEO #scrollH {
+ position: absolute;
+ left: 1px;
+ bottom: -20px;
+ width: calc(100% - 2px);
+ height: 18px;
+}
+
+.NEO #scrollV {
+ position: absolute;
+ right: -20px;
+ top: 1px;
+ width: 18px;
+ height: calc(100% - 2px);
+}
+
+.NEO #scrollH div {
+ position: absolute;
+ width: 50px;
+ height: 16px;
+}
+
+.NEO #scrollV div {
+ position: absolute;
+ width: 16px;
+ height: 50px;
+}
+
+.NEO #scrollH div:hover {}
+.NEO #scrollV div:hover {}
+
+.NEO #neoWarning {
+ position: absolute;
+ left: 5px;
+ top: 5px;
+ color: red;
+ pointer-events: none;
+ text-align: left;
+ transition: all 2s;
+}
+
+/*
+-----------------------
+ Widgets
+-----------------------
+*/
+
+.NEO .buttonOff {
+ display: inline-block;
+ border: 1px solid white;
+ height: 19px;
+ padding: 3px;
+ height: 16px;
+ font-size: 15px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ margin-right: 4px;
+
+ border-left: 1px solid rgba(0, 0, 0, 0);
+ border-top: 1px solid rgba(0, 0, 0, 0);
+ border-right: 1px solid rgba(0, 0, 0, 0);
+ border-bottom: 1px solid rgba(0, 0, 0, 0);
+
+ -webkit-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+ margin: 1px;
+
+}
+
+.NEO .buttonOff:hover {}
+
+.NEO .buttonOff:active,
+.NEO .buttonOn {
+ display: inline-block;
+ height: 19px;
+ padding: 3px;
+ height: 16px;
+ font-size: 15px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ margin-right: 4px;
+
+ border-right: 1px solid rgba(0, 0, 0, 0);
+ border-bottom: 1px solid rgba(0, 0, 0, 0);
+
+ -webkit-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+ margin: 1px;
+}
+
+.NEO .toolTipOff,
+.NEO .toolTipFixed {
+ position:relative;
+ padding: 0;
+ margin: 0;
+ margin-top: 3px;
+ margin-bottom: 3px;
+
+ width: 46px;
+ height: 18px;
+ border-top: 1px solid #ffffff;
+ border-left: 1px solid #ffffff;
+ border-right: 1px solid #9397b2;
+ border-bottom: 1px solid #9397b2;
+}
+
+.NEO .toolTipOn {
+ position:relative;
+ padding: 0;
+ margin: 0;
+ margin-top: 3px;
+ margin-bottom: 3px;
+
+ width: 46px;
+ height: 18px;
+ border-top: 1px solid rgba(0, 0, 0, 0);
+ border-left: 1px solid rgba(0, 0, 0, 0);
+ border-right: 1px solid #ffffff;
+ border-bottom: 1px solid #ffffff;
+}
+
+.NEO .toolTipOff canvas,
+.NEO .toolTipOn canvas,
+.NEO .toolTipFixed canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+
+.NEO .toolTipOff .label,
+.NEO .toolTipOn .label,
+.NEO .toolTipFixed .label {
+ position: absolute;
+ bottom: -4px;
+ left: 1px;
+ font-size:12px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: -1px;
+}
+
+.NEO .colorTips {
+ position:relative;
+ width: 48px;
+ height: 144px;
+ padding: 0;
+ margin: 0;
+ margin-top: 4px;
+ margin-left: 0px;
+}
+
+.NEO .colorTipOff {
+ position: absolute;
+ overflow: hidden;
+ width: 22px;
+ height: 18px;
+ margin: -1px 4px 0px 0px;
+ padding: 0;
+}
+
+.NEO .colorTipOff img {
+ left: 0;
+ opacity: 0.5;
+ position: absolute;
+ pointer-events:none;
+}
+
+.NEO .colorTipOn {
+ position: absolute;
+ overflow: hidden;
+ width: 22px;
+ height: 18px;
+ margin: -1px 4px 0px 0px;
+ padding: 0;
+}
+
+.NEO .colorTipOn img {
+ left: -22px;
+ opacity: 0.5;
+ position: absolute;
+ pointer-events:none;
+}
+
+.NEO .colorSlider {
+ width: 48px;
+ height:13px;
+ position: relative;
+ margin-top: 3px;
+}
+
+.NEO .colorSlider .label {
+ pointer-events: none;
+ position: absolute;
+ left: 2px;
+ bottom: -3px;
+ font-size:12px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: middle;
+}
+
+.NEO .colorSlider .slider {
+ position: absolute;
+ height: 100%;
+ left: 0px;
+ width: 50%;
+ background-color: #fa9696;
+ box-shadow: -1px 0 0 0px rgba(0, 0, 0, 0.3) inset;
+}
+
+.NEO .colorSlider .hit {
+ position:absolute;
+ width: 60px;
+ height: 13px;
+ left: -6px;
+ background-color: white;
+ opacity: 0.01;
+}
+
+.NEO .sizeSlider {
+ width: 48px;
+ height:33px;
+ position: relative;
+ margin-top: 4px;
+}
+
+.NEO .sizeSlider .label {
+ pointer-events: none;
+ position: absolute;
+ left: 2px;
+ bottom: -3px;
+ font-size:12px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: middle;
+}
+
+.NEO .sizeSlider .slider {
+ position: absolute;
+ width: 100%;
+ top: 0px;
+ height: 33%;
+ background-color: #82f238;
+ box-shadow: 0 -1px 0 0px rgba(0, 0, 0, 0.3) inset;
+}
+
+.NEO .sizeSlider .hit {
+ position:absolute;
+ width: 48px;
+ height: 41px;
+ top: -4px;
+ background-color: white;
+ opacity: 0.01;
+}
+
+.NEO .reserveControl {
+ width: 48px;
+ height: 13px;
+ position: relative;
+}
+
+.NEO .reserveControl .reserve {
+ position: absolute;
+ width: 11px;
+ height: 8px;
+ background-color: white;
+}
+
+.NEO .layerControl {
+ width: 48px;
+ height: 20px;
+ position: relative;
+ margin-top: 6px;
+}
+
+.NEO .layerControl .bg {
+ position: absolute;
+ width: 44px;
+ height: 9px;
+ margin: 0;
+
+ top: 0px;
+ left: 2px;
+}
+
+.NEO .layerControl .line1 {
+ position: absolute;
+ width: 50px;
+ height:10px;
+ margin: 0;
+ padding: 0;
+
+ top: 0px;
+ left: -1px;
+ background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent);
+}
+
+.NEO .layerControl .line0 {
+ position: absolute;
+ width: 50px;
+ height: 10px;
+ margin: 0;
+ padding: 0;
+
+ top: 10px;
+ left: -1px;
+ background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent);
+}
+
+.NEO .layerControl .label1 {
+ position: absolute;
+ left: 2px;
+ Top: -4px;
+ font-size:11px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: baseline;
+}
+
+.NEO .layerControl .label0 {
+ position: absolute;
+ left: 2px;
+ Top: 6px;
+ font-size:11px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: baseline;
+}
+
+/*
+-----------------------
+ InputText
+-----------------------
+*/
+
+.NEO .inputText {
+ z-index: 100000;
+ position: absolute;
+
+ text-align: left;
+ white-space: nowrap;
+ color: #0000ff;
+
+ font-family: 'Arial';
+ padding: 1px 5px 1px 5px;
+ font-size: 32px;
+
+ line-height: 40px;
+ height: 40px;
+ min-width: 10em;
+
+ bottom: 0px;
+ left: 250px;
+
+ border: 1px solid #aaa;
+ background-color: white;
+}
+
+*[contenteditable] {
+ user-select: auto !important;
+ -webkit-user-select: auto !important;
+ -moz-user-select: auto !important;
+}
+
+#testtext {
+ user-select: auto !important;
+ -webkit-user-select: auto !important;
+ -moz-user-select: auto;
+}
+
+[contenteditable="true"]:focus {
+ outline: 1px solid #b1d6fd;
+ border: 1px solid #b1d6fd;
+}
diff --git a/static/js/paintbbs/PaintBBS-1.1.11.js b/static/js/paintbbs/PaintBBS-1.1.11.js
new file mode 100644
index 0000000..8ca50e7
--- /dev/null
+++ b/static/js/paintbbs/PaintBBS-1.1.11.js
@@ -0,0 +1,5686 @@
+'use strict';
+
+document.addEventListener("DOMContentLoaded", function() {
+ Neo.init();
+
+ if (!navigator.userAgent.match("Electron")) {
+ Neo.start();
+ }
+});
+
+
+var Neo = function() {};
+
+Neo.version = "1.1.11";
+Neo.painter;
+Neo.fullScreen = false;
+Neo.uploaded = false;
+
+Neo.config = {
+ width: 300,
+ height: 300,
+
+ color_bk: "#ccccff",
+ color_bk2: "#bbbbff",
+ color_tool_icon: "#e8dfae",
+ color_icon: "#ccccff",
+ color_iconselect: "#ffaaaa",
+ color_text: "#666699",
+ color_bar: "#6f6fae",
+
+ tool_color_button: "#e8dfae",
+ tool_color_button2: "#f8daaa",
+ tool_color_text: "#773333",
+ tool_color_bar: "#ddddff",
+ tool_color_frame: "#000000",
+
+ colors: [
+ "#000000", "#FFFFFF",
+ "#B47575", "#888888",
+ "#FA9696", "#C096C0",
+ "#FFB6FF", "#8080FF",
+ "#25C7C9", "#E7E58D",
+ "#E7962D", "#99CB7B",
+ "#FCECE2", "#F9DDCF"
+ ]
+};
+
+Neo.reservePen = {};
+Neo.reserveEraser = {};
+
+Neo.SLIDERTYPE_RED = 0;
+Neo.SLIDERTYPE_GREEN = 1;
+Neo.SLIDERTYPE_BLUE = 2;
+Neo.SLIDERTYPE_ALPHA = 3;
+Neo.SLIDERTYPE_SIZE = 4;
+
+document.neo = Neo;
+
+Neo.init = function() {
+ var applets = document.getElementsByTagName('applet');
+ if (applets.length == 0) {
+ applets = document.getElementsByTagName('applet-dummy');
+ }
+
+ for (var i = 0; i < applets.length; i++) {
+ var applet = applets[i];
+ var name = applet.attributes.name.value;
+ if (name == "paintbbs") {
+ Neo.applet = applet;
+ Neo.createContainer(applet);
+ Neo.initConfig(applet);
+ Neo.init2();
+ }
+ }
+};
+
+Neo.init2 = function() {
+ var pageview = document.getElementById("pageView");
+ pageview.style.width = Neo.config.applet_width + "px";
+ pageview.style.height = Neo.config.applet_height + "px";
+
+ Neo.canvas = document.getElementById("canvas");
+ Neo.container = document.getElementById("container");
+ Neo.toolsWrapper = document.getElementById("toolsWrapper");
+
+ Neo.painter = new Neo.Painter();
+ Neo.painter.build(Neo.canvas, Neo.config.width, Neo.config.height);
+
+ Neo.container.oncontextmenu = function() {return false;};
+
+ // 続きから描く
+ if (Neo.config.image_canvas) {
+ Neo.painter.loadImage(Neo.config.image_canvas);
+ }
+
+ // 描きかけの画像が見つかったとき
+ if (sessionStorage.getItem('timestamp')) {
+ setTimeout(function () {
+ if (confirm("¿Cargar datos guardados?")) {
+ Neo.painter.loadSession();
+ }
+ }, 1);
+ }
+
+ window.addEventListener("beforeunload", function(e) {
+ if (!Neo.uploaded) {
+ Neo.painter.saveSession();
+ } else {
+ Neo.painter.clearSession();
+ }
+ }, false);
+}
+
+Neo.initConfig = function(applet) {
+ if (applet) {
+ var name = applet.attributes.name.value || "neo";
+ var appletWidth = applet.attributes.width;
+ var appletHeight = applet.attributes.height;
+ if (appletWidth) Neo.config.applet_width = parseInt(appletWidth.value);
+ if (appletHeight) Neo.config.applet_height = parseInt(appletHeight.value);
+
+ var params = applet.getElementsByTagName('param');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i];
+ Neo.config[p.name] = Neo.fixConfig(p.value);
+
+ if (p.name == "image_width") Neo.config.width = parseInt(p.value);
+ if (p.name == "image_height") Neo.config.height = parseInt(p.value);
+ }
+
+ var e = document.getElementById("container");
+ Neo.config.inherit_color = Neo.getInheritColor(e);
+ if (!Neo.config.color_frame) Neo.config.color_frame = Neo.config.color_text;
+ }
+
+ Neo.config.reserves = [
+ { size:1,
+ color:"#000000", alpha:1.0,
+ tool:Neo.Painter.TOOLTYPE_PEN,
+ drawType:Neo.Painter.DRAWTYPE_FREEHAND
+ },
+ { size:5,
+ color:"#FFFFFF", alpha:1.0,
+ tool:Neo.Painter.TOOLTYPE_ERASER,
+ drawType:Neo.Painter.DRAWTYPE_FREEHAND
+ },
+ { size:10,
+ color:"#FFFFFF", alpha:1.0,
+ tool:Neo.Painter.TOOLTYPE_ERASER,
+ drawType:Neo.Painter.DRAWTYPE_FREEHAND
+ },
+ ];
+
+ Neo.reservePen = Neo.clone(Neo.config.reserves[0]);
+ Neo.reserveEraser = Neo.clone(Neo.config.reserves[1]);
+};
+
+Neo.fixConfig = function(value) {
+ // javaでは"#12345"を色として解釈するがjavascriptでは"#012345"に変換しないとだめ
+ if (value.match(/^#[0-9a-fA-F]{5}$/)) {
+ value = "#0" + value.slice(1);
+ }
+ return value;
+};
+
+Neo.initSkin = function() {
+ var sheet = document.styleSheets[0];
+ if (!sheet) {
+ var style = document.createElement("style");
+ document.head.appendChild(style); // must append before you can access sheet property
+ sheet = style.sheet;
+ }
+
+ Neo.styleSheet = sheet;
+
+ var lightBorder = Neo.multColor(Neo.config.color_icon, 1.3);
+ var darkBorder = Neo.multColor(Neo.config.color_icon, 0.7);
+ var lightBar = Neo.multColor(Neo.config.color_bar, 1.3);
+ var darkBar = Neo.multColor(Neo.config.color_bar, 0.7);
+ var bgImage = Neo.backgroundImage();
+
+ Neo.addRule(".NEO #container", "background-image", "url(" + bgImage + ")");
+ Neo.addRule(".NEO .colorSlider .label", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .sizeSlider .label", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .layerControl .label1", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .layerControl .label0", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .toolTipOn .label", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .toolTipOff .label", "color", Neo.config.tool_color_text);
+
+ Neo.addRule(".NEO #toolSet", "background-color", Neo.config.color_bk);
+ Neo.addRule(".NEO #tools", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .layerControl .bg", "border-bottom", "1px solid " + Neo.config.tool_color_text);
+
+ Neo.addRule(".NEO .buttonOn", "color", Neo.config.color_text);
+ Neo.addRule(".NEO .buttonOff", "color", Neo.config.color_text);
+
+ Neo.addRule(".NEO .buttonOff", "background-color", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff", "border-top", "1px solid ", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff", "border-left", "1px solid ", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff", "box-shadow", "0 0 0 1px " + Neo.config.color_icon + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO .buttonOff:hover", "background-color", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff:hover", "border-top", "1px solid " + lightBorder);
+ Neo.addRule(".NEO .buttonOff:hover", "border-left", "1px solid " + lightBorder);
+ Neo.addRule(".NEO .buttonOff:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "background-color", darkBorder);
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-top", "1px solid " + darkBorder);
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-left", "1px solid " + darkBorder);
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO #canvas", "border", "1px solid " + Neo.config.color_frame);
+ Neo.addRule(".NEO #scrollH, .NEO #scrollV", "background-color", Neo.config.color_icon);
+ Neo.addRule(".NEO #scrollH, .NEO #scrollV", "box-shadow", "0 0 0 1px white" + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "background-color", Neo.config.color_bar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "box-shadow", "0 0 0 1px " + Neo.config.color_icon);
+ Neo.addRule(".NEO #scrollH div:hover, .NEO #scrollV div:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect);
+
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-top", "1px solid " + lightBar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-left", "1px solid " + lightBar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-right", "1px solid " + darkBar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-bottom", "1px solid " + darkBar);
+
+ Neo.addRule(".NEO .toolTipOn", "background-color", Neo.multColor(Neo.config.tool_color_button, 0.7));
+ Neo.addRule(".NEO .toolTipOff", "background-color", Neo.config.tool_color_button);
+ Neo.addRule(".NEO .toolTipFixed", "background-color", Neo.config.tool_color_button2);
+
+ Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "background-color", Neo.config.tool_color_bar);
+ Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar);
+ Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar);
+ Neo.addRule(".NEO .layerControl", "background-color", Neo.config.tool_color_bar);
+
+ Neo.addRule(".NEO .colorTipOn, .NEO .colorTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .toolTipOn, .NEO .toolTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .toolTipFixed", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .reserveControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .layerControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .reserveControl .reserve", "border", "1px solid " + Neo.config.tool_color_frame);
+};
+
+Neo.addRule = function(selector, styleName, value, sheet) {
+ if (!sheet) sheet = Neo.styleSheet;
+ if (sheet.addRule) {
+ sheet.addRule(selector, styleName + ":" + value, sheet.rules.length);
+
+ } else if (sheet.insertRule) {
+ var rule = selector + "{" + styleName + ":" + value + "}";
+ var index = sheet.cssRules.length;
+ sheet.insertRule(rule, index);
+ }
+};
+
+Neo.getInheritColor = function(e) {
+ var result = "#000000";
+ while (e && e.style) {
+ if (e.style.color != "") {
+ result = e.style.color;
+ break;
+ }
+ if (e.attributes["text"]) {
+ result = e.attributes["text"].value;
+ break;
+ }
+ e = e.parentNode;
+ }
+ return result;
+};
+
+Neo.backgroundImage = function() {
+ var c1 = Neo.painter.getColor(Neo.config.color_bk) | 0xff000000;
+ var c2 = Neo.painter.getColor(Neo.config.color_bk2) | 0xff000000;
+ var bgCanvas = document.createElement("canvas");
+ bgCanvas.width = 16;
+ bgCanvas.height = 16;
+ var ctx = bgCanvas.getContext("2d");
+ var imageData = ctx.getImageData(0, 0, 16, 16);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var index = 0;
+ for (var y = 0; y < 16; y++) {
+ for (var x = 0; x < 16; x++) {
+ buf32[index++] = (x == 14 || y == 14) ? c2 : c1;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+ return bgCanvas.toDataURL('image/png');
+};
+
+Neo.multColor = function(c, scale) {
+ var r = Math.round(parseInt(c.substr(1, 2), 16) * scale);
+ var g = Math.round(parseInt(c.substr(3, 2), 16) * scale);
+ var b = Math.round(parseInt(c.substr(5, 2), 16) * scale);
+ r = ("0" + Math.min(Math.max(r, 0), 255).toString(16)).substr(-2);
+ g = ("0" + Math.min(Math.max(g, 0), 255).toString(16)).substr(-2);
+ b = ("0" + Math.min(Math.max(b, 0), 255).toString(16)).substr(-2);
+ return '#' + r + g + b;
+};
+
+Neo.initComponents = function() {
+ document.getElementById("copyright").innerHTML += "v" + Neo.version;
+
+ //アプレットのborderの動作をエミュレート
+ if (navigator.userAgent.search("FireFox") > -1) {
+ var container = document.getElementById("container");
+ container.addEventListener("mousedown", function(e) {
+ container.style.borderColor = Neo.config.inherit_color;
+ e.stopPropagation();
+ }, false);
+ document.addEventListener("mousedown", function(e) {
+ container.style.borderColor = 'transparent';
+ }, false);
+ }
+
+ // 投稿に失敗する可能性があるときは警告を表示する
+ Neo.showWarning();
+
+ if (Neo.styleSheet) {
+ Neo.addRule("*", "user-select", "none");
+ Neo.addRule("*", "-webkit-user-select", "none");
+ Neo.addRule("*", "-ms-user-select", "none");
+ }
+}
+
+Neo.initButtons = function() {
+ new Neo.Button().init("undo").onmouseup = function() {
+ new Neo.UndoCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("redo").onmouseup = function () {
+ new Neo.RedoCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("window").onmouseup = function() {
+ new Neo.WindowCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("submit").onmouseup = function() {
+ new Neo.SubmitCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("copyright").onmouseup = function() {
+ new Neo.CopyrightCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("zoomPlus").onmouseup = function() {
+ new Neo.ZoomPlusCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("zoomMinus").onmouseup = function() {
+ new Neo.ZoomMinusCommand(Neo.painter).execute();
+ };
+
+ Neo.fillButton = new Neo.Button().init("fill", {type:'fill'});
+
+ // toolTip
+ Neo.penTip = new Neo.PenTip().init("pen");
+ Neo.pen2Tip = new Neo.Pen2Tip().init("pen2");
+ Neo.effectTip = new Neo.EffectTip().init("effect");
+ Neo.effect2Tip = new Neo.Effect2Tip().init("effect2");
+ Neo.eraserTip = new Neo.EraserTip().init("eraser");
+ Neo.drawTip = new Neo.DrawTip().init("draw");
+ Neo.maskTip = new Neo.MaskTip().init("mask");
+
+ Neo.toolButtons = [Neo.fillButton,
+ Neo.penTip,
+ Neo.pen2Tip,
+ Neo.effectTip,
+ Neo.effect2Tip,
+ Neo.drawTip,
+ Neo.eraserTip];
+
+ // colorTip
+ for (var i = 1; i <= 14; i++) {
+ new Neo.ColorTip().init("color" + i, {index:i});
+ };
+
+ // colorSlider
+ Neo.sliders[Neo.SLIDERTYPE_RED] = new Neo.ColorSlider().init(
+ "sliderRed", {type:Neo.SLIDERTYPE_RED});
+ Neo.sliders[Neo.SLIDERTYPE_GREEN] = new Neo.ColorSlider().init(
+ "sliderGreen", {type:Neo.SLIDERTYPE_GREEN});
+ Neo.sliders[Neo.SLIDERTYPE_BLUE] = new Neo.ColorSlider().init(
+ "sliderBlue", {type:Neo.SLIDERTYPE_BLUE});
+ Neo.sliders[Neo.SLIDERTYPE_ALPHA] = new Neo.ColorSlider().init(
+ "sliderAlpha", {type:Neo.SLIDERTYPE_ALPHA});
+
+ // sizeSlider
+ Neo.sliders[Neo.SLIDERTYPE_SIZE] = new Neo.SizeSlider().init(
+ "sliderSize", {type:Neo.SLIDERTYPE_SIZE});
+
+ // reserveControl
+ for (var i = 1; i <= 3; i++) {
+ new Neo.ReserveControl().init("reserve" + i, {index:i});
+ };
+
+ new Neo.LayerControl().init("layerControl");
+ new Neo.ScrollBarButton().init("scrollH");
+ new Neo.ScrollBarButton().init("scrollV");
+};
+
+Neo.start = function(isApp) {
+ if (!Neo.painter) return;
+
+ Neo.initSkin();
+ Neo.initComponents();
+ Neo.initButtons();
+
+ Neo.isApp = isApp;
+ if (Neo.applet) {
+ var name = Neo.applet.attributes.name.value || "paintbbs";
+ Neo.applet.outerHTML = "";
+ document[name] = Neo;
+
+ Neo.resizeCanvas();
+ Neo.container.style.visibility = "visible";
+
+ if (Neo.isApp) {
+ var ipc = require('electron').ipcRenderer;
+ ipc.sendToHost('neo-status', 'ok');
+ }
+ }
+};
+
+Neo.showWarning = function() {
+ var futaba = location.hostname.match(/2chan.net/i);
+ var samplebbs = location.hostname.match(/neo.websozai.jp/i);
+
+ var chrome = navigator.userAgent.match(/Chrome\/(\d+)/i);
+ if (chrome && chrome.length > 1) chrome = chrome[1];
+
+ var edge = navigator.userAgent.match(/Edge\/(\d+)/i);
+ if (edge && edge.length > 1) edge = edge[1];
+
+ var ms = false;
+ if (/MSIE 10/i.test(navigator.userAgent)) {
+ ms = true; // This is internet explorer 10
+ }
+ if (/MSIE 9/i.test(navigator.userAgent) ||
+ /rv:11.0/i.test(navigator.userAgent)) {
+ ms = true; // This is internet explorer 9 or 11
+ }
+
+ var str = "";
+ if (futaba || samplebbs) {
+ if (ms || (edge && edge < 15)) {
+ str = "このブラウザでは<br>投稿に失敗することがあります<br>";
+ }
+ }
+
+ // もし<PARAM NAME="neo_warning" VALUE="...">があれば表示する
+ if (Neo.config.neo_warning) {
+ str += Neo.config.neo_warning;
+ }
+
+ var warning = document.getElementById("neoWarning")
+ warning.innerHTML = str;
+ setTimeout(function() { warning.style.opacity = "0"; }, 15000);
+};
+
+/*
+-----------------------------------------------------------------------
+UIの更新
+-----------------------------------------------------------------------
+*/
+
+Neo.updateUI = function() {
+ var current = Neo.painter.tool.getToolButton();
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ if (current) {
+ if (current == toolTip) {
+ toolTip.setSelected(true);
+ toolTip.update();
+ } else {
+ toolTip.setSelected(false);
+ }
+ }
+ }
+ if (Neo.drawTip) {
+ Neo.drawTip.update();
+ }
+
+ Neo.updateUIColor(true, false);
+}
+
+Neo.updateUIColor = function(updateSlider, updateColorTip) {
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ toolTip.update();
+ }
+
+ if (updateSlider) {
+ for (var i = 0; i < Neo.sliders.length; i++) {
+ var slider = Neo.sliders[i];
+ slider.update();
+ }
+ }
+
+ // パレットを変更するとき
+ if (updateColorTip) {
+ var colorTip = Neo.ColorTip.getCurrent();
+ if (colorTip) {
+ colorTip.setColor(Neo.painter.foregroundColor);
+ }
+ }
+};
+
+/*
+-----------------------------------------------------------------------
+リサイズ対応
+-----------------------------------------------------------------------
+*/
+
+Neo.updateWindow = function() {
+ if (Neo.fullScreen) {
+ document.getElementById("windowView").style.display = "block";
+ document.getElementById("windowView").appendChild(Neo.container);
+
+ } else {
+ document.getElementById("windowView").style.display = "none";
+ document.getElementById("pageView").appendChild(Neo.container);
+ }
+ Neo.resizeCanvas();
+};
+
+Neo.resizeCanvas = function() {
+ var appletWidth = Neo.container.clientWidth;
+ var appletHeight = Neo.container.clientHeight;
+
+ var canvasWidth = Neo.painter.canvasWidth;
+ var canvasHeight = Neo.painter.canvasHeight;
+
+ var width0 = canvasWidth * Neo.painter.zoom;
+ var height0 = canvasHeight * Neo.painter.zoom;
+
+ var width = (width0 < appletWidth - 100) ? width0 : appletWidth - 100;
+ var height = (height0 < appletHeight - 120) ? height0 : appletHeight - 120;
+
+ //width, heightは偶数でないと誤差が出るため
+ width = Math.floor(width / 2) * 2;
+ height = Math.floor(height / 2) * 2;
+
+ Neo.painter.destWidth = width;
+ Neo.painter.destHeight = height;
+
+ Neo.painter.destCanvas.width = width;
+ Neo.painter.destCanvas.height = height;
+ Neo.painter.destCanvasCtx = Neo.painter.destCanvas.getContext("2d");
+ Neo.painter.destCanvasCtx.imageSmoothingEnabled = false;
+ Neo.painter.destCanvasCtx.mozImageSmoothingEnabled = false;
+
+ Neo.canvas.style.width = width + "px";
+ Neo.canvas.style.height = height + "px";
+
+ var top = (Neo.container.clientHeight - toolsWrapper.clientHeight) / 2;
+ Neo.toolsWrapper.style.top = ((top > 0) ? top : 0) + "px";
+
+ if (top < 0) {
+ var s = Neo.container.clientHeight / toolsWrapper.clientHeight;
+ Neo.toolsWrapper.style.transform =
+ "translate(0, " + top + "px) scale(1," + s + ")";
+ } else {
+ Neo.toolsWrapper.style.transform = "";
+ }
+
+ Neo.painter.setZoom(Neo.painter.zoom);
+ Neo.painter.updateDestCanvas(0, 0, canvasWidth, canvasHeight);
+};
+
+/*
+-----------------------------------------------------------------------
+投稿
+-----------------------------------------------------------------------
+*/
+
+Neo.clone = function(src) {
+ var dst = {};
+ for (var k in src) {
+ dst[k] = src[k];
+ }
+ return dst;
+};
+
+Neo.getSizeString = function(len) {
+ var result = String(len);
+ while (result.length < 8) {
+ result = "0" + result;
+ }
+ return result;
+};
+
+Neo.openURL = function(url) {
+ if (Neo.isApp) {
+ require('electron').shell.openExternal(url);
+
+ } else {
+ location.href = url;
+ }
+};
+
+Neo.submit = function(board, blob, thumbnail, thumbnail2) {
+ var url = Neo.config.url_save;
+ console.log("submit url=" + url);
+
+ var headerString = Neo.config.send_header || "";
+ var imageType = Neo.config.send_header_image_type;
+ if (imageType && imageType == "true") {
+ headerString = "image_type=png&" + headerString
+ console.log("header=" + headerString);
+ }
+
+ var header = new Blob([headerString]);
+ var headerLength = this.getSizeString(header.size);
+ var imgLength = this.getSizeString(blob.size);
+
+ var array = ['P', // PaintBBS
+ headerLength,
+ header,
+ imgLength,
+ '\r\n',
+ blob];
+
+ if (thumbnail) {
+ var thumbnailLength = this.getSizeString(thumbnail.size);
+ array.push(thumbnailLength, thumbnail);
+ }
+ if (thumbnail2) {
+ var thumbnail2Length = this.getSizeString(thumbnail2.size);
+ array.push(thumbnail2Length, thumbnail2);
+ }
+
+ var body = new Blob(array, {type: 'application/octet-binary'}); //これが必要!!
+
+ var request = new XMLHttpRequest();
+ request.open("POST", url, true);
+
+ request.onload = function(e) {
+ console.log(request.response);
+ Neo.uploaded = true;
+
+ var url = Neo.config.url_exit;
+ /*if (url[0] == '/') {
+ url = url.replace(/^.*\//, ''); //よくわかんないけどとりあえず
+ }*/
+
+ // ふたばのpaintpost.phpは、画像投稿に成功するとresponseに
+ // "./futaba.php?mode=paintcom&amp;painttmp=.png"
+ // という文字列を返します。
+ //
+ // NEOでは、responseに文字列"painttmp="が含まれる場合は
+ // <PARAM>で指定されたurl_exitを無視して、このURLにジャンプします。
+ var responseURL = request.response.replace(/&amp;/g, '&');
+ if (responseURL.match(/painttmp=/)) {
+ url = responseURL;
+ }
+ //var exitURL = board + url;
+ var exitURL = url;
+
+ // しぃちゃんのドキュメントをよく見たら
+ // responseが "URL:〜" の形だった場合はそこへ飛ばすって書いてありました。
+ // こっちを使うべきでした……
+ if (responseURL.match(/^URL:/)) {
+ exitURL = responseURL.replace(/^URL:/, '');
+ }
+
+ location.href = exitURL;
+ };
+ request.onerror = function(e) {
+ console.log("error");
+ };
+ request.onabort = function(e) {
+ console.log("abort");
+ };
+ request.ontimeout = function(e) {
+ console.log("timeout");
+ };
+
+ if (0) { // データのデバッグのため送信するデータをuint8arrayにコピーしておく
+ var fr = new FileReader();
+ fr.onload = function () {
+ var result = fr.result;
+ }
+ fr.readAsArrayBuffer(body);
+ }
+
+ request.send(body);
+};
+
+/*
+-----------------------------------------------------------------------
+LiveConnect
+-----------------------------------------------------------------------
+*/
+
+Neo.getColors = function() {
+ console.log("getColors");
+ return Neo.config.colors.join('\n');
+};
+
+Neo.setColors = function(colors) {
+ console.log("setColors");
+ var array = colors.split('\n');
+ for (var i = 0; i < 14; i++) {
+ var color = array[i];
+ Neo.config.colors[i] = color;
+ Neo.colorTips[i].setColor(color);
+ }
+};
+
+/*
+-----------------------------------------------------------------------
+DOMツリーの作成
+-----------------------------------------------------------------------
+*/
+
+Neo.createContainer = function(applet) {
+ var neo = document.createElement("div");
+ neo.className = "NEO";
+ neo.id = "NEO";
+ neo.innerHTML = (function() {/*
+
+<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
+
+<div id="pageView" style="width:450px; height:470px; margin:auto;">
+ <div id="container" style="visibility:hidden;">
+ <div id="center">
+ <div id="painterContainer">
+ <div id="painterWrapper">
+ <div id="upper">
+ <div id="redo">Rehacer</div>
+ <div id="undo">Deshacer</div>
+ <div id="fill">Llenar</div>
+ </div>
+ <div id="painter">
+ <div id="canvas">
+ <div id="scrollH"></div>
+ <div id="scrollV"></div>
+ <div id="zoomPlusWrapper">
+ <div id="zoomPlus">+</div>
+ </div>
+ <div id="zoomMinusWrapper">
+ <div id="zoomMinus">-</div>
+ </div>
+ <div id="neoWarning"></div>
+ </div>
+ </div>
+ <div id="lower">
+ </div>
+ </div>
+ <div id="toolsWrapper">
+ <div id="tools">
+ <div id="toolSet">
+ <div id="pen"></div>
+ <div id="pen2"></div>
+ <div id="effect"></div>
+ <div id="effect2"></div>
+ <div id="eraser"></div>
+ <div id="draw"></div>
+ <div id="mask"></div>
+
+ <div class="colorTips">
+ <div id="color2"></div><div id="color1"></div><br>
+ <div id="color4"></div><div id="color3"></div><br>
+ <div id="color6"></div><div id="color5"></div><br>
+ <div id="color8"></div><div id="color7"></div><br>
+ <div id="color10"></div><div id="color9"></div><br>
+ <div id="color12"></div><div id="color11"></div><br>
+ <div id="color14"></div><div id="color13"></div>
+ </div>
+
+ <div id="sliderRed"></div>
+ <div id="sliderGreen"></div>
+ <div id="sliderBlue"></div>
+ <div id="sliderAlpha"></div>
+ <div id="sliderSize"></div>
+
+ <div class="reserveControl" style="margin-top:4px;">
+ <div id="reserve1"></div>
+ <div id="reserve2"></div>
+ <div id="reserve3"></div>
+ </div>
+ <div id="layerControl" style="margin-top:6px;"></div>
+
+ <!--<div id="toolPad" style="height:20px;"></div>-->
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="headerButtons">
+ <div id="window">Ventana</div>
+ </div>
+ <div id="footerButtons">
+ <div id="submit">Enviar</div>
+ <div id="copyright">(C)しいちゃん PaintBBS NEO</div>
+ </div>
+ </div>
+</div>
+
+<div id="windowView" style="display: none;">
+
+</div>
+
+
+*/}).toString().match(/\/\*([^]*)\*\//)[1];
+
+ var parent = applet.parentNode;
+ parent.appendChild(neo);
+ parent.insertBefore(neo, applet);
+
+// applet.style.display = "none";
+
+ // NEOを組み込んだURLをアプリ版で開くとDOMツリーが2重にできて格好悪いので消しておく
+ setTimeout(function() {
+ var tmp = document.getElementsByClassName("NEO");
+ if (tmp.length > 1) {
+ for (var i = 1; i < tmp.length; i++) {
+ tmp[i].style.display = "none";
+ }
+ }
+ }, 0);
+};
+
+
+'use strict';
+
+Neo.Painter = function() {
+ this._undoMgr = new Neo.UndoManager(50);
+};
+
+Neo.Painter.prototype.container;
+Neo.Painter.prototype._undoMgr;
+Neo.Painter.prototype.tool;
+Neo.Painter.prototype.inputText;
+
+//Canvas Info
+Neo.Painter.prototype.canvasWidth;
+Neo.Painter.prototype.canvasHeight;
+Neo.Painter.prototype.canvas = [];
+Neo.Painter.prototype.canvasCtx = [];
+Neo.Painter.prototype.visible = [];
+Neo.Painter.prototype.current = 0;
+
+//Temp Canvas Info
+Neo.Painter.prototype.tempCanvas;
+Neo.Painter.prototype.tempCanvasCtx;
+Neo.Painter.prototype.tempX = 0;
+Neo.Painter.prototype.tempY = 0;
+
+//Destination Canvas for display
+Neo.Painter.prototype.destCanvas;
+Neo.Painter.prototype.destCanvasCtx;
+
+
+Neo.Painter.prototype.backgroundColor = "#ffffff";
+Neo.Painter.prototype.foregroundColor = "#000000";
+
+Neo.Painter.prototype.lineWidth = 1;
+Neo.Painter.prototype.alpha = 1;
+Neo.Painter.prototype.zoom = 1;
+Neo.Painter.prototype.zoomX = 0;
+Neo.Painter.prototype.zoomY = 0;
+
+Neo.Painter.prototype.isMouseDown;
+Neo.Painter.prototype.isMouseDownRight;
+Neo.Painter.prototype.prevMouseX;
+Neo.Painter.prototype.prevMouseY;
+Neo.Painter.prototype.mouseX;
+Neo.Painter.prototype.mouseY;
+
+Neo.Painter.prototype.slowX = 0;
+Neo.Painter.prototype.slowY = 0;
+Neo.Painter.prototype.stab = null;
+
+Neo.Painter.prototype.isShiftDown = false;
+Neo.Painter.prototype.isCtrlDown = false;
+Neo.Painter.prototype.isAltDown = false;
+
+//Neo.Painter.prototype.onUpdateCanvas;
+Neo.Painter.prototype._roundData = [];
+Neo.Painter.prototype._toneData = [];
+Neo.Painter.prototype.toolStack = [];
+
+Neo.Painter.prototype.maskType = 0;
+Neo.Painter.prototype.drawType = 0;
+Neo.Painter.prototype.maskColor = "#000000";
+Neo.Painter.prototype._currentColor = [];
+Neo.Painter.prototype._currentMask = [];
+
+Neo.Painter.prototype.aerr;
+
+Neo.Painter.LINETYPE_NONE = 0;
+Neo.Painter.LINETYPE_PEN = 1;
+Neo.Painter.LINETYPE_ERASER = 2;
+Neo.Painter.LINETYPE_BRUSH = 3;
+Neo.Painter.LINETYPE_TONE = 4;
+Neo.Painter.LINETYPE_DODGE = 5;
+Neo.Painter.LINETYPE_BURN = 6;
+
+Neo.Painter.MASKTYPE_NONE = 0;
+Neo.Painter.MASKTYPE_NORMAL = 1;
+Neo.Painter.MASKTYPE_REVERSE = 2;
+Neo.Painter.MASKTYPE_ADD = 3;
+Neo.Painter.MASKTYPE_SUB = 4;
+
+Neo.Painter.DRAWTYPE_FREEHAND = 0;
+Neo.Painter.DRAWTYPE_LINE = 1;
+Neo.Painter.DRAWTYPE_BEZIER = 2;
+
+Neo.Painter.ALPHATYPE_NONE = 0;
+Neo.Painter.ALPHATYPE_PEN = 1;
+Neo.Painter.ALPHATYPE_FILL = 2;
+Neo.Painter.ALPHATYPE_BRUSH = 3;
+
+Neo.Painter.TOOLTYPE_NONE = 0;
+Neo.Painter.TOOLTYPE_PEN = 1;
+Neo.Painter.TOOLTYPE_ERASER = 2;
+Neo.Painter.TOOLTYPE_HAND = 3;
+Neo.Painter.TOOLTYPE_SLIDER = 4;
+Neo.Painter.TOOLTYPE_FILL = 5;
+Neo.Painter.TOOLTYPE_MASK = 6;
+Neo.Painter.TOOLTYPE_ERASEALL = 7;
+Neo.Painter.TOOLTYPE_ERASERECT = 8;
+Neo.Painter.TOOLTYPE_COPY = 9;
+Neo.Painter.TOOLTYPE_PASTE = 10;
+Neo.Painter.TOOLTYPE_MERGE = 11;
+Neo.Painter.TOOLTYPE_FLIP_H = 12;
+Neo.Painter.TOOLTYPE_FLIP_V = 13;
+
+Neo.Painter.TOOLTYPE_BRUSH = 14;
+Neo.Painter.TOOLTYPE_TEXT = 15;
+Neo.Painter.TOOLTYPE_TONE = 16;
+Neo.Painter.TOOLTYPE_BLUR = 17;
+Neo.Painter.TOOLTYPE_DODGE = 18;
+Neo.Painter.TOOLTYPE_BURN = 19;
+Neo.Painter.TOOLTYPE_RECT = 20;
+Neo.Painter.TOOLTYPE_RECTFILL = 21;
+Neo.Painter.TOOLTYPE_ELLIPSE = 22;
+Neo.Painter.TOOLTYPE_ELLIPSEFILL = 23;
+Neo.Painter.TOOLTYPE_BLURRECT = 24;
+Neo.Painter.TOOLTYPE_TURN = 25;
+
+Neo.Painter.prototype.build = function(div, width, height)
+{
+ this.container = div;
+ this._initCanvas(div, width, height);
+ this._initRoundData();
+ this._initToneData();
+ this._initInputText();
+
+ this.setTool(new Neo.PenTool());
+
+};
+
+Neo.Painter.prototype.setTool = function(tool) {
+ if (this.tool && this.tool.saveStates) this.tool.saveStates();
+
+ if (this.tool && this.tool.kill) {
+ this.tool.kill();
+ }
+ this.tool = tool;
+ tool.init();
+ if (this.tool && this.tool.loadStates) this.tool.loadStates();
+};
+
+Neo.Painter.prototype.pushTool = function(tool) {
+ this.toolStack.push(this.tool);
+ this.tool = tool;
+ tool.init();
+};
+
+Neo.Painter.prototype.popTool = function() {
+ var tool = this.tool;
+ if (tool && tool.kill) {
+ tool.kill();
+ }
+ this.tool = this.toolStack.pop();
+};
+
+Neo.Painter.prototype.getCurrentTool = function() {
+ if (this.tool) {
+ var tool = this.tool;
+ if (tool && tool.type == Neo.Painter.TOOLTYPE_SLIDER) {
+ var stack = this.toolStack;
+ if (stack.length > 0) {
+ tool = stack[stack.length - 1];
+ }
+ }
+ return tool;
+ }
+ return null;
+};
+
+Neo.Painter.prototype.setToolByType = function(toolType) {
+ switch (parseInt(toolType)) {
+ case Neo.Painter.TOOLTYPE_PEN: this.setTool(new Neo.PenTool()); break;
+ case Neo.Painter.TOOLTYPE_ERASER: this.setTool(new Neo.EraserTool()); break;
+ case Neo.Painter.TOOLTYPE_HAND: this.setTool(new Neo.HandTool()); break;
+ case Neo.Painter.TOOLTYPE_FILL: this.setTool(new Neo.FillTool()); break;
+ case Neo.Painter.TOOLTYPE_ERASEALL: this.setTool(new Neo.EraseAllTool()); break;
+ case Neo.Painter.TOOLTYPE_ERASERECT: this.setTool(new Neo.EraseRectTool()); break;
+
+ case Neo.Painter.TOOLTYPE_COPY: this.setTool(new Neo.CopyTool()); break;
+ case Neo.Painter.TOOLTYPE_PASTE: this.setTool(new Neo.PasteTool()); break;
+ case Neo.Painter.TOOLTYPE_MERGE: this.setTool(new Neo.MergeTool()); break;
+ case Neo.Painter.TOOLTYPE_FLIP_H: this.setTool(new Neo.FlipHTool()); break;
+ case Neo.Painter.TOOLTYPE_FLIP_V: this.setTool(new Neo.FlipVTool()); break;
+
+ case Neo.Painter.TOOLTYPE_BRUSH: this.setTool(new Neo.BrushTool()); break;
+ case Neo.Painter.TOOLTYPE_TEXT: this.setTool(new Neo.TextTool()); break;
+ case Neo.Painter.TOOLTYPE_TONE: this.setTool(new Neo.ToneTool()); break;
+ case Neo.Painter.TOOLTYPE_BLUR: this.setTool(new Neo.BlurTool()); break;
+ case Neo.Painter.TOOLTYPE_DODGE: this.setTool(new Neo.DodgeTool()); break;
+ case Neo.Painter.TOOLTYPE_BURN: this.setTool(new Neo.BurnTool()); break;
+
+ case Neo.Painter.TOOLTYPE_RECT: this.setTool(new Neo.RectTool()); break;
+ case Neo.Painter.TOOLTYPE_RECTFILL: this.setTool(new Neo.RectFillTool()); break;
+ case Neo.Painter.TOOLTYPE_ELLIPSE: this.setTool(new Neo.EllipseTool()); break;
+ case Neo.Painter.TOOLTYPE_ELLIPSEFILL:this.setTool(new Neo.EllipseFillTool()); break;
+ case Neo.Painter.TOOLTYPE_BLURRECT: this.setTool(new Neo.BlurRectTool()); break;
+ case Neo.Painter.TOOLTYPE_TURN: this.setTool(new Neo.TurnTool()); break;
+
+ default:
+ console.log("unknown toolType " + toolType);
+ break;
+ }
+};
+
+Neo.Painter.prototype._initCanvas = function(div, width, height) {
+ width = parseInt(width);
+ height = parseInt(height);
+ var destWidth = parseInt(div.clientWidth);
+ var destHeight = parseInt(div.clientHeight);
+ this.destWidth = width;
+ this.destHeight = height;
+
+ this.canvasWidth = width;
+ this.canvasHeight = height;
+ this.zoomX = width * 0.5;
+ this.zoomY = height * 0.5;
+
+ for (var i = 0; i < 2; i++) {
+ this.canvas[i] = document.createElement("canvas");
+ this.canvas[i].width = width;
+ this.canvas[i].height = height;
+ this.canvasCtx[i] = this.canvas[i].getContext("2d");
+
+ this.canvas[i].style.imageRendering = "pixelated";
+ this.canvasCtx[i].imageSmoothingEnabled = false;
+ this.canvasCtx[i].mozImageSmoothingEnabled = false;
+ this.visible[i] = true;
+ }
+
+ this.tempCanvas = document.createElement("canvas");
+ this.tempCanvas.width = width;
+ this.tempCanvas.height = height;
+ this.tempCanvasCtx = this.tempCanvas.getContext("2d");
+ this.tempCanvas.style.position = "absolute";
+ this.tempCanvas.enabled = false;
+
+ var array = this.container.getElementsByTagName("canvas");
+ if (array.length > 0) {
+ this.destCanvas = array[0];
+ } else {
+ this.destCanvas = document.createElement("canvas");
+ this.container.appendChild(this.destCanvas);
+ }
+
+ this.destCanvasCtx = this.destCanvas.getContext("2d");
+ this.destCanvas.width = destWidth;
+ this.destCanvas.height = destHeight;
+
+ this.destCanvas.style.imageRendering = "pixelated";
+ this.destCanvasCtx.imageSmoothingEnabled = false;
+ this.destCanvasCtx.mozImageSmoothingEnabled = false;
+
+ var ref = this;
+
+ var container = document.getElementById("container");
+
+ if (window.PointerEvent) {
+ container.addEventListener("pointerdown", function(e) {
+ ref._mouseDownHandler(e); });
+ container.addEventListener("pointerup", function(e) {
+ ref._mouseUpHandler(e); });
+ container.addEventListener("pointermove", function(e) {
+ ref._mouseMoveHandler(e); });
+ container.addEventListener("pointerover", function(e) {
+ ref._rollOverHandler(e); });
+ container.addEventListener("pointerout", function(e) {
+ ref._rollOutHandler(e); });
+
+ } else {
+ container.onmousedown = function(e) {ref._mouseDownHandler(e)};
+ container.onmousemove = function(e) {ref._mouseMoveHandler(e)};
+ container.onmouseup = function(e) {ref._mouseUpHandler(e)};
+ container.onmouseover = function(e) {ref._rollOverHandler(e)};
+ container.onmouseout = function(e) {ref._rollOutHandler(e)};
+
+ container.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ }, true);
+ container.addEventListener("touchmove", function(e) {
+ ref._mouseMoveHandler(e);
+ }, true);
+ container.addEventListener("touchend", function(e) {
+ ref._mouseUpHandler(e);
+ }, true);
+ }
+
+ document.onkeydown = function(e) {ref._keyDownHandler(e)};
+ document.onkeyup = function(e) {ref._keyUpHandler(e)};
+
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype._initRoundData = function() {
+ for (var r = 1; r <= 30; r++) {
+ this._roundData[r] = new Uint8Array(r * r);
+ var mask = this._roundData[r];
+ var d = Math.floor(r / 2.0);
+ var index = 0;
+ for (var x = 0; x < r; x++) {
+ for (var y = 0; y < r; y++) {
+ var xx = x + 0.5 - r/2.0;
+ var yy = y + 0.5 - r/2.0;
+ mask[index++] = (xx*xx + yy*yy <= r*r/4) ? 1 : 0;
+ }
+ }
+ }
+ this._roundData[3][0] = 0;
+ this._roundData[3][2] = 0;
+ this._roundData[3][6] = 0;
+ this._roundData[3][8] = 0;
+
+ this._roundData[5][1] = 0;
+ this._roundData[5][3] = 0;
+ this._roundData[5][5] = 0;
+ this._roundData[5][9] = 0;
+ this._roundData[5][15] = 0;
+ this._roundData[5][19] = 0;
+ this._roundData[5][21] = 0;
+ this._roundData[5][23] = 0;
+};
+
+Neo.Painter.prototype._initToneData = function() {
+ var pattern = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];
+
+ for (var i = 0; i < 16; i++) {
+ this._toneData[i] = new Uint8Array(16);
+ for (var j = 0; j < 16; j++) {
+ this._toneData[i][j] = (i >= pattern[j]) ? 1 : 0;
+ }
+ }
+};
+
+Neo.Painter.prototype.getToneData = function(alpha) {
+ var alphaTable = [23,
+ 47,
+ 69,
+ 92,
+ 114,
+ 114,
+ 114,
+ 138,
+ 161,
+ 184,
+ 184,
+ 207,
+ 230,
+ 230,
+ 253,
+ ];
+
+ for (var i = 0; i < alphaTable.length; i++) {
+ if (alpha < alphaTable[i]) {
+ return this._toneData[i];
+ }
+ }
+ return this._toneData[i];
+};
+
+Neo.Painter.prototype._initInputText = function() {
+ var text = document.getElementById("inputtext");
+ if (!text) {
+ text = document.createElement("div");
+ }
+
+ text.id = "inputext";
+ text.setAttribute("contentEditable", true);
+ text.spellcheck = false;
+ text.className = "inputText";
+ text.innerHTML = "";
+
+ text.style.display = "none";
+// text.style.userSelect = "none";
+ Neo.painter.container.appendChild(text);
+ this.inputText = text;
+
+ this.updateInputText();
+};
+
+Neo.Painter.prototype.hideInputText = function() {
+ var text = this.inputText;
+ text.blur();
+ text.style.display = "none";
+};
+
+Neo.Painter.prototype.updateInputText = function() {
+ var text = this.inputText;
+ var d = this.lineWidth;
+ var fontSize = Math.round(d * 55/28 + 7);
+ var height = Math.round(d * 68/28 + 12);
+
+ text.style.fontSize = fontSize + "px";
+ text.style.lineHeight = fontSize + "px";
+ text.style.height = fontSize + "px";
+ text.style.marginTop = -fontSize + "px";
+};
+
+/*
+-----------------------------------------------------------------------
+ Mouse Event Handling
+-----------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype._keyDownHandler = function(e) {
+ this.isShiftDown = e.shiftKey;
+ this.isCtrlDown = e.ctrlKey;
+ this.isAltDown = e.altKey;
+ if (e.keyCode == 32) this.isSpaceDown = true;
+
+ if (!this.isShiftDown && this.isCtrlDown) {
+ if (!this.isAltDown) {
+ if (e.keyCode == 90 || e.keyCode == 85) this.undo(); //Ctrl+Z,Ctrl.U
+ if (e.keyCode == 89) this.redo(); //Ctrl+Y
+ } else {
+ if (e.keyCode == 90) this.redo(); //Ctrl+Alt+Z
+ }
+ }
+
+ if (!this.isShiftDown && !this.isCtrlDown && !this.isAltDown) {
+ if (e.keyCode == 107) new Neo.ZoomPlusCommand(this).execute(); // +
+ if (e.keyCode == 109) new Neo.ZoomMinusCommand(this).execute(); // -
+ }
+
+ if (this.tool.keyDownHandler) {
+ this.tool.keyDownHandler(e);
+ }
+
+ //スペース・Shift+スペースででスクロールしないように
+ if (document.activeElement != this.inputText) e.preventDefault();
+};
+
+Neo.Painter.prototype._keyUpHandler = function(e) {
+ this.isShiftDown = e.shiftKey;
+ this.isCtrlDown = e.ctrlKey;
+ this.isAltDown = e.altKey;
+ if (e.keyCode == 32) this.isSpaceDown = false;
+
+ if (this.tool.keyUpHandler) {
+ this.tool.keyUpHandler(oe);
+ }
+};
+
+Neo.Painter.prototype._rollOverHandler = function(e) {
+ if (this.tool.rollOverHandler) {
+ this.tool.rollOverHandler(this);
+ }
+};
+
+Neo.Painter.prototype._rollOutHandler = function(e) {
+ if (this.tool.rollOutHandler) {
+ this.tool.rollOutHandler(this);
+ }
+};
+
+Neo.Painter.prototype._mouseDownHandler = function(e) {
+ if (e.target == Neo.painter.destCanvas) {
+ //よくわからないがChromeでドラッグの時カレットが出るのを防ぐ
+ //http://stackoverflow.com/questions/2745028/chrome-sets-cursor-to-text-while-dragging-why
+ e.preventDefault();
+ }
+
+ if (e.button == 2) {
+ this.isMouseDownRight = true;
+
+ } else {
+ if (!e.shiftKey && e.ctrlKey && e.altKey) {
+ this.isMouseDown = true;
+
+ } else {
+ if (e.ctrlKey || e.altKey) {
+ this.isMouseDownRight = true;
+ } else {
+ this.isMouseDown = true;
+ }
+ }
+ }
+
+ this._updateMousePosition(e);
+ this.prevMouseX = this.mouseX;
+ this.prevMouseY = this.mouseY;
+
+ if (this.isMouseDownRight) {
+ this.isMouseDownRight = false;
+ if (!this.isWidget(e.target)) {
+ this.pickColor(this.mouseX, this.mouseY);
+ return;
+ }
+ }
+
+ if (!this.isUIPaused()) {
+ if (e.target['data-bar']) {
+ this.pushTool(new Neo.HandTool());
+
+ } else if (this.isSpaceDown && document.activeElement != this.inputText) {
+ this.pushTool(new Neo.HandTool());
+ this.tool.reverse = true;
+
+ } else if (e.target['data-slider'] != undefined) {
+ this.pushTool(new Neo.SliderTool());
+ this.tool.target = e.target;
+
+ } else if (e.ctrlKey && e.altKey && !e.shiftKey) {
+ this.pushTool(new Neo.SliderTool());
+ this.tool.target = Neo.sliders[Neo.SLIDERTYPE_SIZE].element;
+ this.tool.alt = true;
+
+ } else if (this.isWidget(e.target)) {
+ this.isMouseDown = false;
+ this.pushTool(new Neo.DummyTool());
+ }
+ }
+ this.tool.downHandler(this);
+
+ var ref = this;
+ document.onmouseup = function(e) {
+ ref._mouseUpHandler(e)
+ };
+};
+
+Neo.Painter.prototype._mouseUpHandler = function(e) {
+ this.isMouseDown = false;
+ this.isMouseDownRight = false;
+ this.tool.upHandler(this);
+ document.onmouseup = undefined;
+};
+
+Neo.Painter.prototype._mouseMoveHandler = function(e) {
+ this._updateMousePosition(e);
+
+ if (this.isMouseDown || this.isMouseDownRight) {
+ this.tool.moveHandler(this);
+ } else {
+ if (this.tool.upMoveHandler) {
+ this.tool.upMoveHandler(this);
+ }
+ }
+ this.prevMouseX = this.mouseX;
+ this.prevMouseY = this.mouseY;
+};
+
+
+Neo.Painter.prototype._updateMousePosition = function(e) {
+ var rect = this.destCanvas.getBoundingClientRect();
+ var x = (e.clientX !== undefined) ? e.clientX : e.touches[0].clientX;
+ var y = (e.clientY !== undefined) ? e.clientY : e.touches[0].clientY;
+
+ if (this.zoom <= 0) this.zoom = 1; //なぜか0になることがあるので
+
+ this.mouseX = (x - rect.left) / this.zoom
+ + this.zoomX
+ - this.destCanvas.width * 0.5 / this.zoom;
+ this.mouseY = (y - rect.top) / this.zoom
+ + this.zoomY
+ - this.destCanvas.height * 0.5 / this.zoom;
+
+ if (isNaN(this.prevMouseX)) {
+ this.prevMouseX = this.mouseX;
+ }
+ if (isNaN(this.prevMouseY)) {
+ this.prevMosueY = this.mouseY;
+ }
+
+ this.slowX = this.slowX * 0.8 + this.mouseX * 0.2;
+ this.slowY = this.slowY * 0.8 + this.mouseY * 0.2;
+ var now = new Date().getTime();
+ if (this.stab) {
+ var pause = this.stab[3];
+ if (pause) {
+ // ポーズ中
+ if (now > pause) {
+ this.stab = [this.slowX, this.slowY, now];
+ }
+
+ } else {
+ // ポーズされていないとき
+ var prev = this.stab[2];
+ if (now - prev > 150) { // 150ms以上止まっていたらポーズをオンにする
+ this.stab[3] = now + 200 // 200msペンの位置を固定
+
+ } else {
+ this.stab = [this.slowX, this.slowY, now];
+ }
+ }
+ } else {
+ this.stab = [this.slowX, this.slowY, now];
+ }
+
+ this.rawMouseX = x;
+ this.rawMouseY = y;
+ this.clipMouseX = Math.max(Math.min(this.canvasWidth, this.mouseX), 0);
+ this.clipMouseY = Math.max(Math.min(this.canvasHeight, this.mouseY), 0);
+};
+
+Neo.Painter.prototype._beforeUnloadHandler = function(e) {
+ // quick save
+};
+
+Neo.Painter.prototype.getStabilized = function() {
+ return this.stab;
+};
+
+/*
+-------------------------------------------------------------------------
+ Undo
+-------------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.undo = function() {
+ var undoItem = this._undoMgr.popUndo();
+ if (undoItem) {
+ this._pushRedo();
+ this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y);
+ this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y);
+ this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height);
+ }
+};
+
+Neo.Painter.prototype.redo = function() {
+ var undoItem = this._undoMgr.popRedo();
+ if (undoItem) {
+ this._pushUndo(0,0,this.canvasWidth, this.canvasHeight, true);
+ this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y);
+ this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y);
+ this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height);
+ }
+};
+
+Neo.Painter.prototype.hasUndo = function() {
+ return true;
+};
+
+Neo.Painter.prototype._pushUndo = function(x, y, w, h, holdRedo) {
+ x = (x == undefined) ? 0 : x;
+ y = (y == undefined) ? 0 : y;
+ w = (w == undefined) ? this.canvasWidth : w;
+ h = (h == undefined) ? this.canvasHeight : h;
+ var undoItem = new Neo.UndoItem();
+ undoItem.x = 0;
+ undoItem.y = 0;
+ undoItem.width = w;
+ undoItem.height = h;
+ undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h),
+ this.canvasCtx[1].getImageData(x, y, w, h)];
+ this._undoMgr.pushUndo(undoItem, holdRedo);
+};
+
+Neo.Painter.prototype._pushRedo = function(x, y, w, h) {
+ x = (x == undefined) ? 0 : x;
+ y = (y == undefined) ? 0 : y;
+ w = (w == undefined) ? this.canvasWidth : w;
+ h = (h == undefined) ? this.canvasHeight : h;
+ var undoItem = new Neo.UndoItem();
+ undoItem.x = 0;
+ undoItem.y = 0;
+ undoItem.width = w;
+ undoItem.height = h;
+ undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h),
+ this.canvasCtx[1].getImageData(x, y, w, h)];
+ this._undoMgr.pushRedo(undoItem);
+};
+
+
+/*
+-------------------------------------------------------------------------
+ Data Cache for Undo / Redo
+-------------------------------------------------------------------------
+*/
+
+Neo.UndoManager = function(_maxStep){
+ this._maxStep = _maxStep;
+ this._undoItems = [];
+ this._redoItems = [];
+}
+Neo.UndoManager.prototype._maxStep;
+Neo.UndoManager.prototype._redoItems;
+Neo.UndoManager.prototype._undoItems;
+
+//アクションをしてUndo情報を更新
+Neo.UndoManager.prototype.pushUndo = function(undoItem, holdRedo) {
+ this._undoItems.push(undoItem);
+ if (this._undoItems.length > this._maxStep) {
+ this._undoItems.shift();
+ }
+
+ if (!holdRedo == true) {
+ this._redoItems = [];
+ }
+};
+
+Neo.UndoManager.prototype.popUndo = function() {
+ return this._undoItems.pop();
+}
+
+Neo.UndoManager.prototype.pushRedo = function(undoItem) {
+ this._redoItems.push(undoItem);
+}
+
+Neo.UndoManager.prototype.popRedo = function() {
+ return this._redoItems.pop();
+}
+
+
+Neo.UndoItem = function() {}
+Neo.UndoItem.prototype.data;
+Neo.UndoItem.prototype.x;
+Neo.UndoItem.prototype.y;
+Neo.UndoItem.prototype.width;
+Neo.UndoItem.prototype.height;
+
+/*
+-------------------------------------------------------------------------
+ Zoom Controller
+-------------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.setZoom = function(value) {
+ this.zoom = value;
+
+ var container = document.getElementById("container");
+ var width = this.canvasWidth * this.zoom;
+ var height = this.canvasHeight * this.zoom;
+ if (width > container.clientWidth - 100) width = container.clientWidth - 100;
+ if (height > container.clientHeight - 130) height = container.clientHeight - 130;
+ this.destWidth = width;
+ this.destHeight = height;
+
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight, false);
+ this.setZoomPosition(this.zoomX, this.zoomY);
+};
+
+Neo.Painter.prototype.setZoomPosition = function(x, y) {
+ var minx = (this.destCanvas.width / this.zoom) * 0.5;
+ var maxx = this.canvasWidth - minx;
+ var miny = (this.destCanvas.height / this.zoom) * 0.5;
+ var maxy = this.canvasHeight - miny;
+
+
+ x = Math.round(Math.max(Math.min(maxx,x),minx));
+ y = Math.round(Math.max(Math.min(maxy,y),miny));
+
+ this.zoomX = x;
+ this.zoomY = y;
+ this.updateDestCanvas(0,0,this.canvasWidth,this.canvasHeight,false);
+
+ this.scrollBarX = (maxx == minx) ? 0 : (x - minx) / (maxx - minx);
+ this.scrollBarY = (maxy == miny) ? 0 : (y - miny) / (maxy - miny);
+ this.scrollWidth = maxx - minx;
+ this.scrollHeight = maxy - miny;
+
+ if (Neo.scrollH) Neo.scrollH.update(this);
+ if (Neo.scrollV) Neo.scrollV.update(this);
+
+ this.hideInputText();
+};
+
+
+/*
+-------------------------------------------------------------------------
+ Drawing Helper
+-------------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.submit = function(board) {
+ var thumbnail = null;
+ var thumbnail2 = null;
+
+ if (this.useThumbnail()) {
+ thumbnail = this.getThumbnail(Neo.config.thumbnail_type || "png");
+ if (Neo.config.thumbnail_type2) {
+ thumbnail2 = this.getThumbnail(Neo.config.thumbnail_type2);
+ }
+ }
+ Neo.submit(board, this.getPNG(), thumbnail2, thumbnail);
+};
+
+Neo.Painter.prototype.useThumbnail = function() {
+ var thumbnailWidth = this.getThumbnailWidth();
+ var thumbnailHeight = this.getThumbnailHeight();
+ if (thumbnailWidth && thumbnailHeight) {
+ if (thumbnailWidth < this.canvasWidth ||
+ thumbnailHeight < this.canvasHeight) {
+ return true;
+ }
+ }
+ return false;
+};
+
+Neo.Painter.prototype.dataURLtoBlob = function(dataURL) {
+ var byteString;
+ if (dataURL.split(',')[0].indexOf('base64') >= 0) {
+ byteString = atob(dataURL.split(',')[1]);
+ } else {
+ byteString = unescape(dataURL.split(',')[1]);
+ }
+
+ // write the bytes of the string to a typed array
+ var ia = new Uint8Array(byteString.length);
+ for (var i = 0; i < byteString.length; i++) {
+ ia[i] = byteString.charCodeAt(i);
+ }
+ return new Blob([ia], {type:'image/png'});
+};
+
+Neo.Painter.prototype.getImage = function(imageWidth, imageHeight) {
+ var width = this.canvasWidth;
+ var height = this.canvasHeight;
+ imageWidth = imageWidth || width;
+ imageHeight = imageHeight || height;
+
+ var pngCanvas = document.createElement("canvas");
+ pngCanvas.width = imageWidth;
+ pngCanvas.height = imageHeight;
+ var pngCanvasCtx = pngCanvas.getContext("2d");
+ pngCanvasCtx.fillStyle = "#ffffff";
+ pngCanvasCtx.fillRect(0, 0, imageWidth, imageHeight);
+
+ if (this.visible[0]) {
+ pngCanvasCtx.drawImage(this.canvas[0],
+ 0, 0, width, height,
+ 0, 0, imageWidth, imageHeight);
+ }
+ if (this.visible[1]) {
+ pngCanvasCtx.drawImage(this.canvas[1],
+ 0, 0, width, height,
+ 0, 0, imageWidth, imageHeight);
+ }
+ return pngCanvas;
+};
+
+Neo.Painter.prototype.getPNG = function() {
+ var image = this.getImage();
+ var dataURL = image.toDataURL('image/png');
+ return this.dataURLtoBlob(dataURL);
+};
+
+Neo.Painter.prototype.getThumbnail = function(type) {
+ if (type != "animation") {
+ var thumbnailWidth = this.getThumbnailWidth();
+ var thumbnailHeight = this.getThumbnailHeight();
+ if (thumbnailWidth || thumbnailHeight) {
+ var width = this.canvasWidth;
+ var height = this.canvasHeight;
+ if (thumbnailWidth == 0) {
+ thumbnailWidth = thumbnailHeight * width / height;
+ }
+ if (thumbnailHeight == 0) {
+ thumbnailHeight = thumbnailWidth * height / width;
+ }
+ } else {
+ thumbnailWidth = thumbnailHeight = null;
+ }
+
+ console.log("get thumbnail", thumbnailWidth, thumbnailHeight);
+
+ var image = this.getImage(thumbnailWidth, thumbnailHeight);
+ var dataURL = image.toDataURL('image/' + type);
+ return this.dataURLtoBlob(dataURL);
+
+ } else {
+ return new Blob([]); //animationには対応していないのでダミーデータを返す
+ }
+};
+
+Neo.Painter.prototype.getThumbnailWidth = function() {
+ var width = Neo.config.thumbnail_width;
+ if (width) {
+ if (width.match(/%$/)) {
+ return Math.floor(this.canvasWidth * (parseInt(width) / 100.0));
+ } else {
+ return parseInt(width);
+ }
+ }
+ return 0;
+};
+
+Neo.Painter.prototype.getThumbnailHeight = function() {
+ var height = Neo.config.thumbnail_height;
+ if (height) {
+ if (height.match(/%$/)) {
+ return Math.floor(this.canvasHeight * (parseInt(height) / 100.0));
+ } else {
+ return parseInt(height);
+ }
+ }
+ return 0;
+};
+
+Neo.Painter.prototype.clearCanvas = function(doConfirm) {
+ if (!doConfirm || confirm("Borrar todo")) {
+ //Register undo first;
+ this._pushUndo();
+
+ this.canvasCtx[0].clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+ this.canvasCtx[1].clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight);
+ }
+};
+
+Neo.Painter.prototype.updateDestCanvas = function(x, y, width, height, useTemp) {
+ var canvasWidth = this.canvasWidth;
+ var canvasHeight = this.canvasHeight;
+ var updateAll = false;
+ if (x == 0 && y == 0 && width == canvasWidth && height == canvasHeight) {
+ updateAll = true;
+ };
+
+ if (x + width > this.canvasWidth) width = this.canvasWidth - x;
+ if (y + height > this.canvasHeight) height = this.canvasHeight - y;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (width <= 0 || height <= 0) return;
+
+ var ctx = this.destCanvasCtx;
+ ctx.save();
+ ctx.fillStyle = "#ffffff";
+
+ if (updateAll) {
+ ctx.fillRect(0, 0, this.destCanvas.width, this.destCanvas.height);
+ } else {
+ //カーソルの描画ゴミが残るのをごまかすため
+ if (x + width == this.canvasWidth) width++;
+ if (y + height == this.canvasHeight) height++;
+ }
+
+ ctx.translate(this.destCanvas.width*.5, this.destCanvas.height*.5);
+ ctx.scale(this.zoom, this.zoom);
+ ctx.translate(-this.zoomX, -this.zoomY);
+ ctx.globalAlpha = 1.0;
+ ctx.msImageSmoothingEnabled = 0;
+
+ if (!updateAll) {
+ ctx.fillRect(x, y, width, height);
+ }
+
+ if (this.visible[0]) {
+ ctx.drawImage(this.canvas[0],
+ x, y, width, height,
+ x, y, width, height);
+ }
+ if (this.visible[1]) {
+ ctx.drawImage(this.canvas[1],
+ x, y, width, height,
+ x, y, width, height);
+ }
+ if (useTemp) {
+ ctx.globalAlpha = 1.0; //this.alpha;
+ ctx.drawImage(this.tempCanvas,
+ x, y, width, height,
+ x + this.tempX, y + this.tempY, width, height);
+ }
+ ctx.restore();
+};
+
+Neo.Painter.prototype.getBound = function(x0, y0, x1, y1, r) {
+ var left = Math.floor((x0 < x1) ? x0 : x1);
+ var top = Math.floor((y0 < y1) ? y0 : y1);
+ var width = Math.ceil(Math.abs(x0 - x1));
+ var height = Math.ceil(Math.abs(y0 - y1));
+ r = Math.ceil(r + 1);
+
+ if (!r) {
+ width += 1;
+ height += 1;
+
+ } else {
+ left -= r;
+ top -= r;
+ width += r * 2;
+ height += r * 2;
+ }
+ return [left, top, width, height];
+};
+
+Neo.Painter.prototype.getColor = function(c) {
+ if (!c) c = this.foregroundColor;
+ var r = parseInt(c.substr(1, 2), 16);
+ var g = parseInt(c.substr(3, 2), 16);
+ var b = parseInt(c.substr(5, 2), 16);
+ var a = Math.floor(this.alpha * 255);
+ return a <<24 | b<<16 | g<<8 | r;
+};
+
+Neo.Painter.prototype.getColorString = function(c) {
+ var rgb = ("000000" + (c & 0xffffff).toString(16)).substr(-6);
+ return '#' + rgb;
+};
+
+Neo.Painter.prototype.setColor = function(c) {
+ if (typeof c != "string") c = this.getColorString(c);
+ this.foregroundColor = c;
+
+ Neo.updateUI();
+};
+
+Neo.Painter.prototype.getAlpha = function(type) {
+ var a1 = this.alpha;
+
+ switch (type) {
+ case Neo.Painter.ALPHATYPE_PEN:
+ if (a1 > 0.5) {
+ a1 = 1.0/16 + (a1 - 0.5) * 30.0/16;
+ } else {
+ a1 = Math.sqrt(2 * a1) / 16.0;
+ }
+ a1 = Math.min(1, Math.max(0, a1));
+ break;
+
+ case Neo.Painter.ALPHATYPE_FILL:
+ a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042;
+ a1 = Math.min(1.0, Math.max(0, a1 * 10));
+ break;
+
+ case Neo.Painter.ALPHATYPE_BRUSH:
+ a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042;
+ a1 = Math.min(1.0, Math.max(0, a1));
+ break;
+ }
+
+ // アルファが小さい時は適当に点を抜いて見た目の濃度を合わせる
+ if (a1 < 1.0/255) {
+ this.aerr += a1;
+ a1 = 0;
+ while (this.aerr > 1.0/255) {
+ a1 = 1.0/255;
+ this.aerr -= 1.0/255;
+ }
+ }
+ return a1;
+};
+
+Neo.Painter.prototype.prepareDrawing = function () {
+ var r = parseInt(this.foregroundColor.substr(1, 2), 16);
+ var g = parseInt(this.foregroundColor.substr(3, 2), 16);
+ var b = parseInt(this.foregroundColor.substr(5, 2), 16);
+ var a = Math.floor(this.alpha * 255);
+
+ var maskR = parseInt(this.maskColor.substr(1, 2), 16);
+ var maskG = parseInt(this.maskColor.substr(3, 2), 16);
+ var maskB = parseInt(this.maskColor.substr(5, 2), 16);
+
+ this._currentColor = [r, g, b, a];
+ this._currentMask = [maskR, maskG, maskB];
+};
+
+Neo.Painter.prototype.isMasked = function (buf8, index) {
+ var r = this._currentMask[0];
+ var g = this._currentMask[1];
+ var b = this._currentMask[2];
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3];
+
+ if (a0 == 0) {
+ r0 = 0xff;
+ g0 = 0xff;
+ b0 = 0xff;
+ }
+
+ var type = this.maskType;
+
+ //TODO
+ //いろいろ試したのですが半透明で描画するときの加算・逆加算を再現する方法がわかりません。
+ //とりあえず単純に無視しています。
+ if (type == Neo.Painter.MASKTYPE_ADD ||
+ type == Neo.Painter.MASKTYPE_SUB) {
+ if (this._currentColor[3] < 250) {
+ type = Neo.Painter.MASKTYPE_NONE;
+ }
+ }
+
+ switch (type) {
+ case Neo.Painter.MASKTYPE_NONE:
+ return;
+
+ case Neo.Painter.MASKTYPE_NORMAL:
+ return (r0 == r &&
+ g0 == g &&
+ b0 == b) ? true : false;
+
+ case Neo.Painter.MASKTYPE_REVERSE:
+ return (r0 != r ||
+ g0 != g ||
+ b0 != b) ? true : false;
+
+ case Neo.Painter.MASKTYPE_ADD:
+ if (a0 > 0) {
+ var sort = this.sortColor(r0, g0, b0);
+ for (var i = 0; i < 3; i++) {
+ var c = sort[i];
+ if (buf8[index + c] < this._currentColor[c]) return true;
+ }
+ return false;
+
+ } else {
+ return false;
+ }
+
+ case Neo.Painter.MASKTYPE_SUB:
+ if (a0 > 0) {
+ var sort = this.sortColor(r0, g0, b0);
+ for (var i = 0; i < 3; i++) {
+ var c = sort[i];
+ if (buf8[index + c] > this._currentColor[c]) return true;
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+};
+
+Neo.Painter.prototype.setPoint = function(buf8, bufWidth, x0, y0, left, top, type) {
+ var x = x0 - left;
+ var y = y0 - top;
+
+ switch (type) {
+ case Neo.Painter.LINETYPE_PEN:
+ this.setPenPoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_BRUSH:
+ this.setBrushPoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_TONE:
+ this.setTonePoint(buf8, bufWidth, x, y, x0, y0);
+ break;
+
+ case Neo.Painter.LINETYPE_ERASER:
+ this.setEraserPoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_BLUR:
+ this.setBlurPoint(buf8, bufWidth, x, y, x0, y0);
+ break;
+
+ case Neo.Painter.LINETYPE_DODGE:
+ this.setDodgePoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_BURN:
+ this.setBurnPoint(buf8, bufWidth, x, y);
+ break;
+
+ default:
+ break;
+ }
+};
+
+
+Neo.Painter.prototype.setPenPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_PEN);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+ if (a > 0) {
+ var a1x = Math.max(a1, 1.0/255);
+
+ var r = (r1 * a1x + r0 * a0 * (1 - a1x)) / a;
+ var g = (g1 * a1x + g0 * a0 * (1 - a1x)) / a;
+ var b = (b1 * a1x + b0 * a0 * (1 - a1x)) / a;
+
+ r = (r1 > r0) ? Math.ceil(r) : Math.floor(r);
+ g = (g1 > g0) ? Math.ceil(g) : Math.floor(g);
+ b = (b1 > b0) ? Math.ceil(b) : Math.floor(b);
+ }
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setBrushPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+ if (a > 0) {
+ var a1x = Math.max(a1, 1.0/255);
+
+ var r = (r1 * a1x + r0 * a0) / (a0 + a1x);
+ var g = (g1 * a1x + g0 * a0) / (a0 + a1x);
+ var b = (b1 * a1x + b0 * a0) / (a0 + a1x);
+
+ r = (r1 > r0) ? Math.ceil(r) : Math.floor(r);
+ g = (g1 > g0) ? Math.ceil(g) : Math.floor(g);
+ b = (b1 > b0) ? Math.ceil(b) : Math.floor(b);
+ }
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setTonePoint = function(buf8, width, x, y, x0, y0) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ if (r0%2) { x0++; y0++; } //なぜか模様がずれるので
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+ var index = (y * width + x) * 4;
+
+ var r = this._currentColor[0];
+ var g = this._currentColor[1];
+ var b = this._currentColor[2];
+ var a = this._currentColor[3];
+
+ var toneData = this.getToneData(a);
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ if (toneData[((y0+i)%4) + (((x0+j)%4) * 4)]) {
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = 255;
+ }
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setEraserPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+ var index = (y * width + x) * 4;
+ var a = Math.floor(this.alpha * 255);
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var k = (buf8[index + 3] / 255.0) * (1.0 - (a / 255.0));
+
+ buf8[index + 3] -= a / (d * (255.0 - a) / 255.0);
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setBlurPoint = function(buf8, width, x, y, x0, y0) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+ var height = buf8.length / (width * 4);
+
+// var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ var a1 = this.alpha / 12;
+ if (a1 == 0) return;
+ var blur = a1;
+
+ var tmp = new Uint8ClampedArray(buf8.length);
+ for (var i = 0; i < buf8.length; i++) {
+ tmp[i] = buf8[i];
+ }
+
+ var left = x0 - x - r0;
+ var top = y0 - y - r0;
+
+ var xstart = 0, xend = d;
+ var ystart = 0, yend = d;
+ if (xstart > left) xstart = -left;
+ if (ystart > top) ystart = -top;
+ if (xend > this.canvasWidth - left) xend = this.canvasWidth - left;
+ if (yend > this.canvasHeight - top) yend = this.canvasHeight - top;
+
+ for (var j = ystart; j < yend; j++) {
+ var index = (j * width + xstart) * 4;
+ for (var i = xstart; i < xend; i++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var rgba = [0, 0, 0, 0, 0];
+
+ this.addBlur(tmp, index, 1.0 - blur*4, rgba);
+ if (i > xstart) this.addBlur(tmp, index - 4, blur, rgba);
+ if (i < xend - 1) this.addBlur(tmp, index + 4, blur, rgba);
+ if (j > ystart) this.addBlur(tmp, index - width*4, blur, rgba);
+ if (j < yend - 1) this.addBlur(tmp, index + width*4, blur, rgba);
+
+ buf8[index + 0] = Math.round(rgba[0]);
+ buf8[index + 1] = Math.round(rgba[1]);
+ buf8[index + 2] = Math.round(rgba[2]);
+ buf8[index + 3] = Math.round((rgba[3] / rgba[4]) * 255.0);
+ }
+ index += 4;
+ }
+ }
+};
+
+Neo.Painter.prototype.setDodgePoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ if (a1 != 255.0) {
+ var r1 = r0 * 255 / (255 - a1);
+ var g1 = g0 * 255 / (255 - a1);
+ var b1 = b0 * 255 / (255 - a1);
+ } else {
+ var r1 = 255.0;
+ var g1 = 255.0;
+ var b1 = 255.0;
+ }
+
+ var r = Math.ceil(r1);
+ var g = Math.ceil(g1);
+ var b = Math.ceil(b1);
+ var a = a0;
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setBurnPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ if (a1 != 255.0) {
+ var r1 = 255 - (255 - r0) * 255 / (255 - a1);
+ var g1 = 255 - (255 - g0) * 255 / (255 - a1);
+ var b1 = 255 - (255 - b0) * 255 / (255 - a1);
+ } else {
+ var r1 = 0;
+ var g1 = 0;
+ var b1 = 0;
+ }
+
+ var r = Math.floor(r1);
+ var g = Math.floor(g1);
+ var b = Math.floor(b1);
+ var a = a0;
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+
+Neo.Painter.prototype.xorPixel = function(buf32, bufWidth, x, y, c) {
+ var index = y * bufWidth + x;
+ if (!c) c = 0xffffff;
+ buf32[index] ^= c;
+};
+
+Neo.Painter.prototype.getBezierPoint = function(t, x0, y0, x1, y1, x2, y2, x3, y3) {
+ var a0 = (1 - t) * (1 - t) * (1 - t);
+ var a1 = (1 - t) * (1 - t) * t * 3;
+ var a2 = (1 - t) * t * t * 3;
+ var a3 = t * t * t;
+
+ var x = x0 * a0 + x1 * a1 + x2 * a2 + x3 * a3;
+ var y = y0 * a0 + y1 * a1 + y2 * a2 + y3 * a3;
+ return [x, y];
+};
+
+var nmax = 1;
+
+Neo.Painter.prototype.drawBezier = function(ctx, x0, y0, x1, y1, x2, y2, x3, y3, type) {
+ var xmax = Math.max(x0, x1, x2, x3);
+ var xmin = Math.min(x0, x1, x2, x3);
+ var ymax = Math.max(y0, y1, y2, y3);
+ var ymin = Math.min(y0, y1, y2, y3);
+ var n = Math.ceil(((xmax - xmin) + (ymax - ymin)) * 2.5);
+
+ if (n > nmax) {
+ n = (n < nmax * 2) ? n : nmax * 2;
+ nmax = n;
+ }
+
+ for (var i = 0; i < n; i++) {
+ var t = i * 1.0 / n;
+ var p = this.getBezierPoint(t, x0, y0, x1, y1, x2, y2, x3, y3);
+ this.drawPoint(ctx, p[0], p[1], type);
+ }
+};
+
+Neo.Painter.prototype.prevLine = null; // 始点または終点が2度プロットされることがあるので
+Neo.Painter.prototype.drawLine = function(ctx, x0, y0, x1, y1, type) {
+ x0 = Math.round(x0);
+ x1 = Math.round(x1);
+ y0 = Math.round(y0);
+ y1 = Math.round(y1);
+ var prev = [x0, y0, x1, y1];
+
+ var width = Math.abs(x1 - x0);
+ var height = Math.abs(y1 - y0);
+ var r = Math.ceil(this.lineWidth / 2);
+
+ var left = ((x0 < x1) ? x0 : x1) - r;
+ var top = ((y0 < y1) ? y0 : y1) - r;
+
+ var imageData = ctx.getImageData(left, top, width + r*2, height + r*2);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var dx = width, sx = x0 < x1 ? 1 : -1;
+ var dy = height, sy = y0 < y1 ? 1 : -1;
+ var err = (dx > dy ? dx : -dy) / 2;
+ this.aerr = 0;
+
+ while (true) {
+ if (this.prevLine == null ||
+ !((this.prevLine[0] == x0 && this.prevLine[1] == y0) ||
+ (this.prevLine[2] == x0 && this.prevLine[3] == y0))) {
+ this.setPoint(buf8, imageData.width, x0, y0, left, top, type);
+ }
+
+ if (x0 === x1 && y0 === y1) break;
+ var e2 = err;
+ if (e2 > -dx) { err -= dy; x0 += sx; }
+ if (e2 < dy) { err += dx; y0 += sy; }
+ }
+
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, left, top);
+
+ this.prevLine = prev;
+};
+
+Neo.Painter.prototype.drawPoint = function(ctx, x, y, type) {
+ this.drawLine(ctx, x, y, x, y, type);
+};
+
+Neo.Painter.prototype.xorRect = function(buf32, bufWidth, x, y, width, height, c) {
+ var index = y * bufWidth + x;
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ buf32[index] ^= c;
+ index++;
+ }
+ index += width - bufWidth;
+ }
+};
+
+Neo.Painter.prototype.drawXORRect = function(ctx, x, y, width, height, isFill, c) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+ if (width == 0 || height == 0) return;
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var index = 0;
+ if (!c) c = 0xffffff;
+
+ if (isFill) {
+ this.xorRect(buf32, width, 0, 0, width, height, c);
+
+ } else {
+ for (var i = 0; i < width; i++) { //top
+ buf32[index] = buf32[index] ^= c;
+ index++;
+ }
+ if (height > 1) {
+ index = width;
+ for (var i = 1; i < height; i++) { //left
+ buf32[index] = buf32[index] ^= c;
+ index += width;
+ }
+ if (width > 1) {
+ index = width * 2 - 1;
+ for (var i = 1; i < height - 1; i++) { //right
+ buf32[index] = buf32[index] ^= c;
+ index += width;
+ }
+ index = width * (height - 1) + 1;
+ for (var i = 1; i < width; i++) { // bottom
+ buf32[index] = buf32[index] ^= c;
+ index++;
+ }
+ }
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.drawXOREllipse = function(ctx, x, y, width, height, isFill, c) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+ if (width == 0 || height == 0) return;
+ if (!c) c = 0xffffff;
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+
+ var a = width-1, b = height-1, b1 = b&1; /* values of diameter */
+ var dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
+ var err = dx+dy+b1*a*a, e2; /* error of 1.step */
+
+ var x0 = x;
+ var y0 = y;
+ var x1 = x0+a;
+ var y1 = y0+b;
+
+ if (x0 > x1) { x0 = x1; x1 += a; }
+ if (y0 > y1) y0 = y1;
+ y0 += Math.floor((b+1)/2); y1 = y0-b1; /* starting pixel */
+ a *= 8*a; b1 = 8*b*b;
+ var ymin = y0 - 1;
+
+ do {
+ if (isFill) {
+ if (ymin < y0) {
+ this.xorRect(buf32, width, x0-x, y0 - y, x1 - x0, 1, c);
+ if (y0 != y1) {
+ this.xorRect(buf32, width, x0-x, y1 - y, x1 - x0, 1, c);
+ }
+ ymin = y0;
+ }
+ } else {
+ this.xorPixel(buf32, width, x1-x, y0-y, c);
+ if (x0 != x1) {
+ this.xorPixel(buf32, width, x0-x, y0-y, c);
+ }
+ if (y0 != y1) {
+ this.xorPixel(buf32, width, x0-x, y1-y, c);
+ if (x0 != x1) {
+ this.xorPixel(buf32, width, x1-x, y1-y, c);
+ }
+ }
+ }
+ e2 = 2*err;
+ if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */
+ if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */
+ } while (x0 <= x1);
+
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.drawXORLine = function(ctx, x0, y0, x1, y1, c) {
+ x0 = Math.round(x0);
+ x1 = Math.round(x1);
+ y0 = Math.round(y0);
+ y1 = Math.round(y1);
+
+ var width = Math.abs(x1 - x0);
+ var height = Math.abs(y1 - y0);
+
+ var left = ((x0 < x1) ? x0 : x1);
+ var top = ((y0 < y1) ? y0 : y1);
+// console.log("left:"+left+" top:"+top+" width:"+width+" height:"+height);
+
+ var imageData = ctx.getImageData(left, top, width + 1, height + 1);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var dx = width, sx = x0 < x1 ? 1 : -1;
+ var dy = height, sy = y0 < y1 ? 1 : -1;
+ var err = (dx > dy ? dx : -dy) / 2;
+
+ while (true) {
+ if (this.prevLine == null ||
+ !((this.prevLine[0] == x0 && this.prevLine[1] == y0) ||
+ (this.prevLine[2] == x0 && this.prevLine[3] == y0))) {
+
+ this.xorPixel(buf32, imageData.width, x0 - left, y0 - top, c);
+ }
+
+ if (x0 === x1 && y0 === y1) break;
+ var e2 = err;
+ if (e2 > -dx) { err -= dy; x0 += sx; }
+ if (e2 < dy) { err += dx; y0 += sy; }
+ }
+
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, left, top);
+};
+
+
+Neo.Painter.prototype.eraseRect = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var index = 0;
+
+ var a = 1.0 - this.alpha;
+ if (a != 0) {
+ a = Math.ceil(2.0 / a);
+ } else {
+ a = 255;
+ }
+
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ if (!this.isMasked(buf8, index)) {
+ buf8[index + 3] -= a;
+ }
+ index += 4;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.flipH = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var half = Math.floor(width / 2);
+ for (var j = 0; j < height; j++) {
+ var index = j * width;
+ var index2 = index + (width - 1);
+ for (var i = 0; i < half; i++) {
+ var value = buf32[index + i];
+ buf32[index + i] = buf32[index2 -i];
+ buf32[index2 - i] = value;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.flipV = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var half = Math.floor(height / 2);
+ for (var j = 0; j < half; j++) {
+ var index = j * width;
+ var index2 = (height - 1 - j) * width;
+ for (var i = 0; i < width; i++) {
+ var value = buf32[index + i];
+ buf32[index + i] = buf32[index2 + i];
+ buf32[index2 + i] = value;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.merge = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = [];
+ var buf32 = [];
+ var buf8 = [];
+ for (var i = 0; i < 2; i++) {
+ imageData[i] = this.canvasCtx[i].getImageData(x, y, width, height);
+ buf32[i] = new Uint32Array(imageData[i].data.buffer);
+ buf8[i] = new Uint8ClampedArray(imageData[i].data.buffer);
+ }
+
+ var dst = this.current;
+ var src = (dst == 1) ? 0 : 1;
+ var size = width * height;
+ var index = 0;
+ for (var i = 0; i < size; i++) {
+ var r0 = buf8[0][index + 0];
+ var g0 = buf8[0][index + 1];
+ var b0 = buf8[0][index + 2];
+ var a0 = buf8[0][index + 3] / 255.0;
+ var r1 = buf8[1][index + 0];
+ var g1 = buf8[1][index + 1];
+ var b1 = buf8[1][index + 2];
+ var a1 = buf8[1][index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+ if (a > 0) {
+ var r = Math.floor((r1 * a1 + r0 * a0 * (1 - a1)) / a + 0.5);
+ var g = Math.floor((g1 * a1 + g0 * a0 * (1 - a1)) / a + 0.5);
+ var b = Math.floor((b1 * a1 + b0 * a0 * (1 - a1)) / a + 0.5);
+ }
+ buf8[src][index + 0] = 0;
+ buf8[src][index + 1] = 0;
+ buf8[src][index + 2] = 0;
+ buf8[src][index + 3] = 0;
+ buf8[dst][index + 0] = r;
+ buf8[dst][index + 1] = g;
+ buf8[dst][index + 2] = b;
+ buf8[dst][index + 3] = Math.floor(a * 255 + 0.5);
+ index += 4;
+ }
+
+ for (var i = 0; i < 2; i++) {
+ imageData[i].data.set(buf8[i]);
+ this.canvasCtx[i].putImageData(imageData[i], x, y);
+ }
+};
+
+Neo.Painter.prototype.blurRect = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var tmp = new Uint8ClampedArray(buf8.length);
+ for (var i = 0; i < buf8.length; i++) tmp[i] = buf8[i];
+
+ var index = 0;
+ var a1 = this.alpha / 12;
+ var blur = a1;
+
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ var rgba = [0, 0, 0, 0, 0];
+
+ this.addBlur(tmp, index, 1.0 - blur*4, rgba);
+
+ if (i > 0) this.addBlur(tmp, index - 4, blur, rgba);
+ if (i < width - 1) this.addBlur(tmp, index + 4, blur, rgba);
+ if (j > 0) this.addBlur(tmp, index - width*4, blur, rgba);
+ if (j < height - 1) this.addBlur(tmp, index + width*4, blur, rgba);
+
+ var w = rgba[4];
+ buf8[index + 0] = Math.round(rgba[0]);
+ buf8[index + 1] = Math.round(rgba[1]);
+ buf8[index + 2] = Math.round(rgba[2]);
+ buf8[index + 3] = Math.ceil((rgba[3] / w) * 255.0);
+
+ index += 4;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.addBlur = function(buffer, index, a, rgba) {
+ var r0 = rgba[0];
+ var g0 = rgba[1];
+ var b0 = rgba[2];
+ var a0 = rgba[3];
+ var r1 = buffer[index + 0];
+ var g1 = buffer[index + 1];
+ var b1 = buffer[index + 2];
+ var a1 = (buffer[index + 3] / 255.0) * a;
+ rgba[4] += a;
+
+ var a = a0 + a1;
+ if (a > 0) {
+ rgba[0] = (r1 * a1 + r0 * a0) / (a0 + a1);
+ rgba[1] = (g1 * a1 + g0 * a0) / (a0 + a1);
+ rgba[2] = (b1 * a1 + b0 * a0) / (a0 + a1);
+ rgba[3] = a;
+ }
+};
+
+Neo.Painter.prototype.pickColor = function(x, y) {
+ var r = 0xff, g = 0xff, b = 0xff, a;
+
+ x = Math.floor(x);
+ y = Math.floor(y);
+ if (x >= 0 && x < this.canvasWidth &&
+ y >= 0 && y < this.canvasHeight) {
+
+ for (var i = 0; i < 2; i++) {
+ if (this.visible[i]) {
+ var ctx = this.canvasCtx[i];
+ var imageData = ctx.getImageData(x, y, 1, 1);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var a = buf8[3] / 255.0;
+ r = r * (1.0 - a) + buf8[2] * a;
+ g = g * (1.0 - a) + buf8[1] * a;
+ b = b * (1.0 - a) + buf8[0] * a;
+ }
+ }
+ r = Math.max(Math.min(Math.round(r), 255), 0);
+ g = Math.max(Math.min(Math.round(g), 255), 0);
+ b = Math.max(Math.min(Math.round(b), 255), 0);
+ var result = r | g<<8 | b<<16;
+ }
+ this.setColor(result);
+
+
+ if (this.current > 0) {
+ if (a == 0 && (result == 0xffffff || this.getEmulationMode() < 2.16)) {
+ this.setToolByType(Neo.eraserTip.tools[Neo.eraserTip.mode]);
+
+ } else {
+ if (Neo.eraserTip.selected) {
+ this.setToolByType(Neo.penTip.tools[Neo.penTip.mode]);
+ }
+ }
+ }
+};
+
+Neo.Painter.prototype.fillHorizontalLine = function(buf32, x0, x1, y) {
+ var index = y * this.canvasWidth + x0;
+ var fillColor = this.getColor();
+ for (var x = x0; x <= x1; x++) {
+ buf32[index++] = fillColor;
+ }
+};
+
+Neo.Painter.prototype.scanLine = function(x0, x1, y, baseColor, buf32, stack) {
+ var width = this.canvasWidth;
+
+ while (x0 <= x1) {
+ for (; x0 <= x1; x0++) {
+ if (buf32[y * width + x0] == baseColor) break;
+ }
+ if (x1 < x0) break;
+
+ for (; x0 <= x1; x0++) {
+ if (buf32[y * width + x0] != baseColor) break;
+ }
+ stack.push({x:x0 - 1, y: y})
+ }
+};
+
+Neo.Painter.prototype.fill = function(x, y, ctx) {
+ // http://sandbox.serendip.ws/javascript_canvas_scanline_seedfill.html
+ x = Math.round(x);
+ y = Math.round(y);
+
+ var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var width = imageData.width;
+ var stack = [{x: x, y: y}];
+
+ var baseColor = buf32[y * width + x];
+ var fillColor = this.getColor();
+
+ if ((baseColor & 0xffffff00) == 0 ||
+ (baseColor & 0xffffff) != (fillColor & 0xffffff)) {
+ while (stack.length > 0) {
+ var point = stack.pop();
+ var x0 = point.x;
+ var x1 = point.x;
+ var y = point.y;
+
+ if (buf32[y * width + x] == fillColor)
+ break;
+
+ for (; 0 < x0; x0--) {
+ if (buf32[y * width + (x0 - 1)] != baseColor) break;
+ }
+ for (; x1 < this.canvasHeight - 1; x1++) {
+ if (buf32[y * width + (x1 + 1)] != baseColor) break;
+ }
+ this.fillHorizontalLine(buf32, x0, x1, y);
+
+ if (y + 1 < this.canvasHeight) {
+ this.scanLine(x0, x1, y + 1, baseColor, buf32, stack);
+ }
+ if (y - 1 >= 0) {
+ this.scanLine(x0, x1, y - 1, baseColor, buf32, stack);
+ }
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype.copy = function(x, y, width, height) {
+ this.tempX = 0;
+ this.tempY = 0;
+ this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+
+ var imageData = this.canvasCtx[this.current].getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ this.temp = new Uint32Array(buf32.length);
+ for (var i = 0; i < buf32.length; i++) {
+ this.temp[i] = buf32[i];
+ }
+
+ //tempCanvasに乗せる画像を作る
+ imageData = this.tempCanvasCtx.getImageData(x, y, width, height);
+ buf32 = new Uint32Array(imageData.data.buffer);
+ buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ for (var i = 0; i < buf32.length; i++) {
+ if (this.temp[i] >> 24) {
+ buf32[i] = this.temp[i] | 0xff000000;
+ } else {
+ buf32[i] = 0xffffffff;
+ }
+ }
+ imageData.data.set(buf8);
+ this.tempCanvasCtx.putImageData(imageData, x, y);
+};
+
+
+Neo.Painter.prototype.paste = function(x, y, width, height) {
+ var ctx = this.canvasCtx[this.current];
+// console.log(this.tempX, this.tempY);
+
+ var imageData = ctx.getImageData(x + this.tempX, y + this.tempY, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ for (var i = 0; i < buf32.length; i++) {
+ buf32[i] = this.temp[i];
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x + this.tempX, y + this.tempY);
+
+ this.temp = null;
+ this.tempX = 0;
+ this.tempY = 0;
+ this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype.turn = function(x, y, width, height) {
+ var ctx = this.canvasCtx[this.current];
+
+ // 傾けツールのバグを再現するため一番上のラインで対象領域を埋める
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var temp = new Uint32Array(buf32.length);
+
+ var index = 0;
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ temp[index] = buf32[index];
+ if (index >= width) {
+ buf32[index] = buf32[index % width];
+ }
+ index++;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+
+ // 90度回転させて貼り付け
+ imageData = ctx.getImageData(x, y, height, width);
+ buf32 = new Uint32Array(imageData.data.buffer);
+ buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ index = 0;
+ for (var j = height - 1; j >= 0; j--) {
+ for (var i = 0; i < width; i++) {
+ buf32[i * height + j] = temp[index++];
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.doFill = function(ctx, x, y, width, height, maskFunc) {
+ if (Math.round(x) != x) console.log("*");
+ if (Math.round(width) != width) console.log("*");
+ if (Math.round(height) != height) console.log("*");
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var index = 0;
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+ var a1 = this.getAlpha(Neo.ALPHATYPE_FILL);
+
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ if (maskFunc && maskFunc.call(this, i, j, width, height)) {
+ //なぜか加算逆加算は適用されない
+ if (this.maskType >= Neo.Painter.MASKTYPE_ADD ||
+ !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+
+ if (a > 0) {
+ var a1x = a1;
+ var ax = 1 + a0 * (1 - a1x);
+
+ var r = (r1 + r0 * a0 * (1 - a1x)) / ax;
+ var g = (g1 + g0 * a0 * (1 - a1x)) / ax;
+ var b = (b1 + b0 * a0 * (1 - a1x)) / ax
+
+ r = (r1 > r0) ? Math.ceil(r) : Math.floor(r);
+ g = (g1 > g0) ? Math.ceil(g) : Math.floor(g);
+ b = (b1 > b0) ? Math.ceil(b) : Math.floor(b);
+ }
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+ }
+ }
+ index += 4;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.rectFillMask = function(x, y, width, height) {
+ return true;
+};
+
+Neo.Painter.prototype.rectMask = function(x, y, width, height) {
+ var d = this.lineWidth;
+ return (x < d || x > width - 1 - d ||
+ y < d || y > height - 1 - d) ? true : false;
+};
+
+Neo.Painter.prototype.ellipseFillMask = function(x, y, width, height) {
+ var cx = (width - 1) / 2.0;
+ var cy = (height - 1) / 2.0;
+ x = (x - cx) / (cx + 1);
+ y = (y - cy) / (cy + 1);
+
+ return ((x * x) + (y * y) < 1) ? true : false;
+}
+
+Neo.Painter.prototype.ellipseMask = function(x, y, width, height) {
+ var d = this.lineWidth;
+ var cx = (width - 1) / 2.0;
+ var cy = (height - 1) / 2.0;
+
+ if (cx <= d || cy <= d) return this.ellipseFillMask(x, y, width, height);
+
+ var x2 = (x - cx) / (cx - d + 1);
+ var y2 = (y - cy) / (cy - d + 1);
+
+ x = (x - cx) / (cx + 1);
+ y = (y - cy) / (cy + 1);
+
+ if ((x * x) + (y * y) < 1) {
+ if ((x2 * x2) + (y2 * y2) >= 1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+-----------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.getDestCanvasPosition = function(mx, my, isClip, isCenter) {
+ var mx = Math.floor(mx); //Math.round(mx);
+ var my = Math.floor(my); //Math.round(my);
+ if (isCenter) {
+ mx += 0.499;
+ my += 0.499;
+ }
+ var x = (mx - this.zoomX + this.destCanvas.width * 0.5 / this.zoom) * this.zoom;
+ var y = (my - this.zoomY + this.destCanvas.height * 0.5 / this.zoom) * this.zoom;
+
+ if (isClip) {
+ x = Math.max(Math.min(x, this.destCanvas.width), 0);
+ y = Math.max(Math.min(y, this.destCanvas.height), 0);
+ }
+ return {x:x, y:y};
+};
+
+Neo.Painter.prototype.isWidget = function(element) {
+ while (1) {
+ if (element == null ||
+ element.id == "canvas" ||
+ element.id == "container") break;
+
+ if (element.id == "tools" ||
+ element.className == "buttonOn" ||
+ element.className == "buttonOff" ||
+ element.className == "inputText") {
+ return true;
+ }
+ element = element.parentNode;
+ }
+ return false;
+};
+
+
+Neo.Painter.prototype.loadImage = function (filename) {
+ console.log("loadImage " + filename);
+ var img = new Image();
+ img.src = filename;
+ img.onload = function() {
+ var oe = Neo.painter;
+ oe.canvasCtx[0].drawImage(img, 0, 0);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight);
+ };
+}
+
+Neo.Painter.prototype.loadSession = function (filename) {
+ if (sessionStorage) {
+ var img0 = new Image();
+ img0.src = sessionStorage.getItem('layer0');
+ img0.onload = function() {
+ var img1 = new Image();
+ img1.src = sessionStorage.getItem('layer1');
+ img1.onload = function() {
+ var oe = Neo.painter;
+ oe.canvasCtx[0].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.canvasCtx[1].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.canvasCtx[0].drawImage(img0, 0, 0);
+ oe.canvasCtx[1].drawImage(img1, 0, 0);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight);
+ }
+ }
+ }
+};
+
+Neo.Painter.prototype.saveSession = function() {
+ if (sessionStorage) {
+ sessionStorage.setItem('timestamp', +(new Date()));
+ sessionStorage.setItem('layer0', this.canvas[0].toDataURL('image/png'));
+ sessionStorage.setItem('layer1', this.canvas[1].toDataURL('image/png'));
+ }
+};
+
+Neo.Painter.prototype.clearSession = function() {
+ if (sessionStorage) {
+ sessionStorage.removeItem('timestamp');
+ sessionStorage.removeItem('layer0');
+ sessionStorage.removeItem('layer1');
+ }
+};
+
+Neo.Painter.prototype.sortColor = function(r0, g0, b0) {
+ var min = (r0 < g0) ? ((r0 < b0) ? 0 : 2) : ((g0 < b0) ? 1 : 2);
+ var max = (r0 > g0) ? ((r0 > b0) ? 0 : 2) : ((g0 > b0) ? 1 : 2);
+ var mid = (min + max == 1) ? 2 : ((min + max == 2) ? 1 : 0);
+ return [min, mid, max];
+};
+
+Neo.Painter.prototype.doText = function(x, y, string, fontSize) {
+ //テキスト描画
+ //描画位置がずれるので適当に調整
+ var offset = parseInt(fontSize, 10);
+// y -= Math.round((5.0 + offset/8) / this.zoom);
+// x += Math.round(2.0 / this.zoom);
+
+ var ctx = this.tempCanvasCtx;
+ ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+ ctx.save();
+ ctx.translate(x, y);
+// ctx.scale(1/this.zoom, 1/this.zoom);
+
+ ctx.font = fontSize + " Arial";
+ ctx.fillStyle = 0;
+ ctx.fillText(string, 0, 0);
+ ctx.restore();
+
+ // 適当に二値化
+ var c = this.getColor();
+ var r = c & 0xff;
+ var g = (c & 0xff00) >> 8;
+ var b = (c & 0xff0000) >> 16;
+ var a = Math.round(this.alpha * 255.0);
+
+ var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var length = this.canvasWidth * this.canvasHeight;
+ var index = 0;
+ for (var i = 0; i < length; i++) {
+ if (buf8[index + 3] >= 0x60) {
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ } else {
+ buf8[index + 0] = 0;
+ buf8[index + 1] = 0;
+ buf8[index + 2] = 0;
+ buf8[index + 3] = 0;
+ }
+ index += 4;
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+
+ //キャンバスに貼り付け
+ ctx = this.canvasCtx[this.current];
+ ctx.globalAlpha = 1.0;
+ ctx.drawImage(this.tempCanvas,
+ 0, 0, this.canvasWidth, this.canvasHeight,
+ 0, 0, this.canvasWidth, this.canvasHeight);
+
+ this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype.isUIPaused = function() {
+ if (this.drawType == Neo.Painter.DRAWTYPE_BEZIER) {
+ if (this.tool.step && this.tool.step > 0) {
+ return true;
+ }
+ }
+ return false;
+};
+
+Neo.Painter.prototype.getEmulationMode = function() {
+ return parseFloat(Neo.config.neo_emulation_mode || 2.22)
+};
+
+'use strict';
+
+Neo.ToolBase = function() {};
+
+Neo.ToolBase.prototype.startX;
+Neo.ToolBase.prototype.startY;
+Neo.ToolBase.prototype.init = function(oe) {}
+Neo.ToolBase.prototype.kill = function(oe) {}
+Neo.ToolBase.prototype.lineType = Neo.Painter.LINETYPE_NONE;
+
+Neo.ToolBase.prototype.downHandler = function(oe) {
+ this.startX = oe.mouseX;
+ this.startY = oe.mouseY;
+};
+
+Neo.ToolBase.prototype.upHandler = function(oe) {
+};
+
+Neo.ToolBase.prototype.moveHandler = function(oe) {
+};
+
+Neo.ToolBase.prototype.transformForZoom = function(oe) {
+ var ctx = oe.destCanvasCtx;
+ ctx.translate(oe.canvasWidth * 0.5, oe.canvasHeight * 0.5);
+ ctx.scale(oe.zoom, oe.zoom);
+ ctx.translate(-oe.zoomX, -oe.zoomY);
+};
+
+Neo.ToolBase.prototype.getType = function() {
+ return this.type;
+};
+
+Neo.ToolBase.prototype.getToolButton = function() {
+ switch (this.type) {
+ case Neo.Painter.TOOLTYPE_PEN:
+ case Neo.Painter.TOOLTYPE_BRUSH:
+ case Neo.Painter.TOOLTYPE_TEXT:
+ return Neo.penTip;
+
+ case Neo.Painter.TOOLTYPE_TONE:
+ case Neo.Painter.TOOLTYPE_BLUR:
+ case Neo.Painter.TOOLTYPE_DODGE:
+ case Neo.Painter.TOOLTYPE_BURN:
+ return Neo.pen2Tip;
+
+ case Neo.Painter.TOOLTYPE_RECT:
+ case Neo.Painter.TOOLTYPE_RECTFILL:
+ case Neo.Painter.TOOLTYPE_ELLIPSE:
+ case Neo.Painter.TOOLTYPE_ELLIPSEFILL:
+ return Neo.effectTip;
+
+ case Neo.Painter.TOOLTYPE_COPY:
+ case Neo.Painter.TOOLTYPE_MERGE:
+ case Neo.Painter.TOOLTYPE_BLURRECT:
+ case Neo.Painter.TOOLTYPE_FLIP_H:
+ case Neo.Painter.TOOLTYPE_FLIP_V:
+ case Neo.Painter.TOOLTYPE_TURN:
+ return Neo.effect2Tip;
+
+ case Neo.Painter.TOOLTYPE_ERASER:
+ case Neo.Painter.TOOLTYPE_ERASEALL:
+ case Neo.Painter.TOOLTYPE_ERASERECT:
+ return Neo.eraserTip;
+
+ case Neo.Painter.TOOLTYPE_FILL:
+ return Neo.fillButton;
+ }
+ return null;
+};
+
+Neo.ToolBase.prototype.getReserve = function() {
+ switch (this.type) {
+ case Neo.Painter.TOOLTYPE_ERASER:
+ return Neo.reserveEraser;
+
+ case Neo.Painter.TOOLTYPE_PEN:
+ case Neo.Painter.TOOLTYPE_BRUSH:
+ case Neo.Painter.TOOLTYPE_TONE:
+ case Neo.Painter.TOOLTYPE_ERASERECT:
+ case Neo.Painter.TOOLTYPE_ERASEALL:
+ case Neo.Painter.TOOLTYPE_COPY:
+ case Neo.Painter.TOOLTYPE_MERGE:
+ case Neo.Painter.TOOLTYPE_FIP_H:
+ case Neo.Painter.TOOLTYPE_FIP_V:
+
+ case Neo.Painter.TOOLTYPE_DODGE:
+ case Neo.Painter.TOOLTYPE_BURN:
+ case Neo.Painter.TOOLTYPE_BLUR:
+ case Neo.Painter.TOOLTYPE_BLURRECT:
+
+ case Neo.Painter.TOOLTYPE_TEXT:
+ case Neo.Painter.TOOLTYPE_TURN:
+ case Neo.Painter.TOOLTYPE_RECT:
+ case Neo.Painter.TOOLTYPE_RECTFILL:
+ case Neo.Painter.TOOLTYPE_ELLIPSE:
+ case Neo.Painter.TOOLTYPE_ELLIPSEFILL:
+ return Neo.reservePen;
+
+ }
+ return null;
+};
+
+Neo.ToolBase.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.updateUI();
+ }
+};
+
+Neo.ToolBase.prototype.saveStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ reserve.size = Neo.painter.lineWidth;
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ DrawToolBase(描画ツールのベースクラス)
+-------------------------------------------------------------------------
+*/
+
+Neo.DrawToolBase = function() {};
+Neo.DrawToolBase.prototype = new Neo.ToolBase();
+Neo.DrawToolBase.prototype.isUpMove = false;
+Neo.DrawToolBase.prototype.step = 0;
+
+Neo.DrawToolBase.prototype.init = function() {
+ this.step = 0;
+ this.isUpMove = true;
+};
+
+Neo.DrawToolBase.prototype.downHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandDownHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineDownHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierDownHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.upHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandUpHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineUpHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierUpHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.moveHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierMoveHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.upMoveHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandUpMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineUpMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierUpMoveHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.keyDownHandler = function(e) {
+ switch (Neo.painter.drawType) {
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierKeyDownHandler(e); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.rollOverHandler= function(oe) {};
+Neo.DrawToolBase.prototype.rollOutHandler= function(oe) {
+ if (!oe.isMouseDown && !oe.isMouseDownRight){
+ oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+Neo.DrawToolBase.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 1.0;
+ Neo.updateUI();
+ };
+};
+
+
+/* FreeHand (手書き) */
+
+Neo.DrawToolBase.prototype.freeHandDownHandler = function(oe) {
+ //Register undo first;
+ oe._pushUndo();
+
+ oe.prepareDrawing();
+ this.isUpMove = false;
+ var ctx = oe.canvasCtx[oe.current];
+ if (oe.alpha >= 1 || this.lineType != Neo.Painter.LINETYPE_BRUSH) {
+ var x0 = Math.floor(oe.mouseX);
+ var y0 = Math.floor(oe.mouseY);
+ oe.drawLine(ctx, x0, y0, x0, y0, this.lineType);
+ }
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+
+ if (oe.alpha >= 1) {
+ var r = Math.ceil(oe.lineWidth / 2);
+ var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.mouseX, oe.mouseY, r);
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ }
+};
+
+Neo.DrawToolBase.prototype.freeHandUpHandler = function(oe) {
+ oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight);
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+
+// oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+// this.drawCursor(oe);
+ oe.prevLine = null;
+};
+
+Neo.DrawToolBase.prototype.freeHandMoveHandler = function(oe) {
+ var ctx = oe.canvasCtx[oe.current];
+ var x0 = Math.floor(oe.mouseX);
+ var y0 = Math.floor(oe.mouseY);
+ var x1 = Math.floor(oe.prevMouseX);
+ var y1 = Math.floor(oe.prevMouseY);
+ oe.drawLine(ctx, x0, y0, x1, y1, this.lineType);
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+
+ var r = Math.ceil(oe.lineWidth / 2);
+ var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.prevMouseX, oe.prevMouseY, r);
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+};
+
+Neo.DrawToolBase.prototype.freeHandUpMoveHandler = function(oe) {
+ this.isUpMove = true;
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+ this.drawCursor(oe);
+};
+
+Neo.DrawToolBase.prototype.drawCursor = function(oe) {
+ if (oe.lineWidth <= 8) return;
+ var mx = oe.mouseX;
+ var my = oe.mouseY;
+ var d = oe.lineWidth;
+
+ var x = (mx - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom;
+ var y = (my - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom;
+ var r = d * 0.5 * oe.zoom;
+
+ if (!(x > -r &&
+ y > -r &&
+ x < oe.destCanvas.width + r &&
+ y < oe.destCanvas.height + r)) return;
+
+ var ctx = oe.destCanvasCtx;
+ ctx.save();
+ this.transformForZoom(oe)
+
+ var c = (this.type == Neo.Painter.TOOLTYPE_ERASER) ? 0x0000ff : 0xffff7f;
+ oe.drawXOREllipse(ctx, x-r, y-r, r*2, r*2, false, c);
+
+ ctx.restore();
+ oe.cursorRect = oe.getBound(mx, my, mx, my, Math.ceil(d / 2));
+}
+
+
+/* Line (直線) */
+
+Neo.DrawToolBase.prototype.lineDownHandler = function(oe) {
+ this.isUpMove = false;
+ this.startX = Math.floor(oe.mouseX);
+ this.startY = Math.floor(oe.mouseY);
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+};
+
+Neo.DrawToolBase.prototype.lineUpHandler = function(oe) {
+ if (this.isUpMove == false) {
+ this.isUpMove = true;
+
+ oe._pushUndo();
+ oe.prepareDrawing();
+ var ctx = oe.canvasCtx[oe.current];
+ var x0 = Math.floor(oe.mouseX);
+ var y0 = Math.floor(oe.mouseY);
+ oe.drawLine(ctx, x0, y0, this.startX, this.startY, this.lineType);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+Neo.DrawToolBase.prototype.lineMoveHandler = function(oe) {
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ this.drawLineCursor(oe);
+};
+
+Neo.DrawToolBase.prototype.lineUpMoveHandler = function(oe) {
+};
+
+Neo.DrawToolBase.prototype.drawLineCursor = function(oe, mx, my) {
+ if (!mx) mx = Math.floor(oe.mouseX);
+ if (!my) my = Math.floor(oe.mouseY);
+ var nx = this.startX;
+ var ny = this.startY;
+ var ctx = oe.destCanvasCtx;
+ ctx.save();
+ this.transformForZoom(oe)
+
+ var x0 = (mx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom;
+ var y0 = (my +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom;
+ var x1 = (nx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom;
+ var y1 = (ny +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom;
+ oe.drawXORLine(ctx, x0, y0, x1, y1);
+
+ ctx.restore();
+};
+
+
+/* Bezier (BZ曲線) */
+
+Neo.DrawToolBase.prototype.bezierDownHandler = function(oe) {
+ this.isUpMove = false;
+
+ if (this.step == 0) {
+ this.startX = this.x0 = Math.floor(oe.mouseX);
+ this.startY = this.y0 = Math.floor(oe.mouseY);
+ }
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+};
+
+Neo.DrawToolBase.prototype.bezierUpHandler = function(oe) {
+ if (this.isUpMove == false) {
+ this.isUpMove = true;
+ }
+
+ this.step++;
+ switch (this.step) {
+ case 1:
+ oe.prepareDrawing();
+ this.x3 = Math.floor(oe.mouseX);
+ this.y3 = Math.floor(oe.mouseY);
+ break;
+
+ case 2:
+ this.x1 = Math.floor(oe.mouseX);
+ this.y1 = Math.floor(oe.mouseY);
+ break;
+
+ case 3:
+ this.x2 = Math.floor(oe.mouseX);
+ this.y2 = Math.floor(oe.mouseY);
+
+ oe._pushUndo();
+ oe.drawBezier(oe.canvasCtx[oe.current],
+ this.x0, this.y0, this.x1, this.y1,
+ this.x2, this.y2, this.x3, this.y3, this.lineType);
+
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ this.step = 0;
+ break;
+
+ default:
+ this.step = 0;
+ break;
+ }
+};
+
+Neo.DrawToolBase.prototype.bezierMoveHandler = function(oe) {
+ switch (this.step) {
+ case 0:
+ if (!this.isUpMove) {
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false);
+ this.drawLineCursor(oe);
+ }
+ break;
+ case 1:
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false);
+ this.drawBezierCursor1(oe);
+ break;
+
+ case 2:
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false);
+ this.drawBezierCursor2(oe);
+ break;
+ }
+};
+
+Neo.DrawToolBase.prototype.bezierUpMoveHandler = function(oe) {
+ this.bezierMoveHandler(oe);
+};
+
+Neo.DrawToolBase.prototype.bezierKeyDownHandler = function(e) {
+ if (e.keyCode == 27) { //Escでキャンセル
+ this.step = 0;
+
+ var oe = Neo.painter;
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+
+Neo.DrawToolBase.prototype.drawBezierCursor1 = function(oe) {
+ var ctx = oe.destCanvasCtx;
+// var x = oe.mouseX; //Math.floor(oe.mouseX);
+// var y = oe.mouseY; //Math.floor(oe.mouseY);
+ var stab = oe.getStabilized();
+ var x = Math.floor(stab[0]);
+ var y = Math.floor(stab[1]);
+ var p = oe.getDestCanvasPosition(x, y, false, true);
+ var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true);
+ var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true);
+
+ // handle
+ oe.drawXORLine(ctx, p0.x, p0.y, p.x, p.y);
+ oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8);
+ oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8);
+
+ // preview
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.drawBezier(oe.tempCanvasCtx,
+ this.x0, this.y0,
+ x, y,
+ x, y,
+ this.x3, this.y3, this.lineType);
+
+ ctx.save();
+ ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5);
+ ctx.scale(oe.zoom, oe.zoom);
+ ctx.translate(-oe.zoomX, -oe.zoomY);
+ ctx.drawImage(oe.tempCanvas,
+ 0, 0, oe.canvasWidth, oe.canvasHeight,
+ 0, 0, oe.canvasWidth, oe.canvasHeight);
+
+ ctx.restore();
+};
+
+Neo.DrawToolBase.prototype.drawBezierCursor2 = function(oe) {
+ var ctx = oe.destCanvasCtx;
+// var x = oe.mouseX; //Math.floor(oe.mouseX);
+// var y = oe.mouseY; //Math.floor(oe.mouseY);
+ var stab = oe.getStabilized();
+ var x = Math.floor(stab[0]);
+ var y = Math.floor(stab[1]);
+ var p = oe.getDestCanvasPosition(oe.mouseX, oe.mouseY, false, true);
+ var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true);
+ var p1 = oe.getDestCanvasPosition(this.x1, this.y1, false, true);
+ var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true);
+
+ // handle
+ oe.drawXORLine(ctx, p3.x, p3.y, p.x, p.y);
+ oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8);
+ oe.drawXORLine(ctx, p0.x, p0.y, p1.x, p1.y);
+ oe.drawXOREllipse(ctx, p1.x - 4, p1.y - 4, 8, 8);
+ oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8);
+
+ // preview
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.drawBezier(oe.tempCanvasCtx,
+ this.x0, this.y0,
+ this.x1, this.y1,
+ x, y,
+ this.x3, this.y3, this.lineType);
+
+ ctx.save();
+ ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5);
+ ctx.scale(oe.zoom, oe.zoom);
+ ctx.translate(-oe.zoomX, -oe.zoomY);
+ ctx.drawImage(oe.tempCanvas,
+ 0, 0, oe.canvasWidth, oe.canvasHeight,
+ 0, 0, oe.canvasWidth, oe.canvasHeight);
+ ctx.restore();
+};
+
+/*
+-------------------------------------------------------------------------
+ Pen(鉛筆)
+-------------------------------------------------------------------------
+*/
+
+Neo.PenTool = function() {};
+Neo.PenTool.prototype = new Neo.DrawToolBase();
+Neo.PenTool.prototype.type = Neo.Painter.TOOLTYPE_PEN;
+Neo.PenTool.prototype.lineType = Neo.Painter.LINETYPE_PEN;
+
+Neo.PenTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 1.0;
+ Neo.updateUI();
+ };
+}
+
+/*
+-------------------------------------------------------------------------
+ Brush(水彩)
+-------------------------------------------------------------------------
+*/
+
+Neo.BrushTool = function() {};
+Neo.BrushTool.prototype = new Neo.DrawToolBase();
+Neo.BrushTool.prototype.type = Neo.Painter.TOOLTYPE_BRUSH;
+Neo.BrushTool.prototype.lineType = Neo.Painter.LINETYPE_BRUSH;
+
+Neo.BrushTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = this.getAlpha();
+ Neo.updateUI();
+ }
+};
+
+Neo.BrushTool.prototype.getAlpha = function() {
+ var alpha = 241 - Math.floor(Neo.painter.lineWidth / 2) * 6;
+ return alpha / 255.0;
+};
+
+/*
+-------------------------------------------------------------------------
+ Tone(トーン)
+-------------------------------------------------------------------------
+*/
+
+Neo.ToneTool = function() {};
+Neo.ToneTool.prototype = new Neo.DrawToolBase();
+Neo.ToneTool.prototype.type = Neo.Painter.TOOLTYPE_TONE;
+Neo.ToneTool.prototype.lineType = Neo.Painter.LINETYPE_TONE;
+
+Neo.ToneTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 23 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ Eraser(消しペン)
+-------------------------------------------------------------------------
+*/
+
+Neo.EraserTool = function() {};
+Neo.EraserTool.prototype = new Neo.DrawToolBase();
+Neo.EraserTool.prototype.type = Neo.Painter.TOOLTYPE_ERASER;
+Neo.EraserTool.prototype.lineType = Neo.Painter.LINETYPE_ERASER;
+
+
+/*
+-------------------------------------------------------------------------
+ Blur(ぼかし)
+-------------------------------------------------------------------------
+*/
+
+Neo.BlurTool = function() {};
+Neo.BlurTool.prototype = new Neo.DrawToolBase();
+Neo.BlurTool.prototype.type = Neo.Painter.TOOLTYPE_BLUR;
+Neo.BlurTool.prototype.lineType = Neo.Painter.LINETYPE_BLUR;
+
+Neo.BlurTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 128 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ Dodge(覆い焼き)
+-------------------------------------------------------------------------
+*/
+
+Neo.DodgeTool = function() {};
+Neo.DodgeTool.prototype = new Neo.DrawToolBase();
+Neo.DodgeTool.prototype.type = Neo.Painter.TOOLTYPE_DODGE;
+Neo.DodgeTool.prototype.lineType = Neo.Painter.LINETYPE_DODGE;
+
+Neo.DodgeTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 128 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ Burn(焼き込み)
+-------------------------------------------------------------------------
+*/
+
+Neo.BurnTool = function() {};
+Neo.BurnTool.prototype = new Neo.DrawToolBase();
+Neo.BurnTool.prototype.type = Neo.Painter.TOOLTYPE_BURN;
+Neo.BurnTool.prototype.lineType = Neo.Painter.LINETYPE_BURN;
+
+Neo.BurnTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 128 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ Hand(スクロール)
+-------------------------------------------------------------------------
+*/
+
+Neo.HandTool = function() {};
+Neo.HandTool.prototype = new Neo.ToolBase();
+Neo.HandTool.prototype.type = Neo.Painter.TOOLTYPE_HAND;
+Neo.HandTool.prototype.isUpMove = false;
+Neo.HandTool.prototype.reverse = false;
+
+Neo.HandTool.prototype.downHandler = function(oe) {
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+
+ this.isDrag = true;
+ this.startX = oe.rawMouseX;
+ this.startY = oe.rawMouseY;
+};
+
+Neo.HandTool.prototype.upHandler = function(oe) {
+ this.isDrag = false;
+ oe.popTool();
+};
+
+Neo.HandTool.prototype.moveHandler = function(oe) {
+ if (this.isDrag) {
+ var dx = this.startX - oe.rawMouseX;
+ var dy = this.startY - oe.rawMouseY;
+
+ var ax = oe.destCanvas.width / (oe.canvasWidth * oe.zoom);
+ var ay = oe.destCanvas.height / (oe.canvasHeight * oe.zoom);
+ var barWidth = oe.destCanvas.width * ax;
+ var barHeight = oe.destCanvas.height * ay;
+ var scrollWidthInScreen = oe.destCanvas.width - barWidth - 2;
+ var scrollHeightInScreen = oe.destCanvas.height - barHeight - 2;
+
+ dx *= oe.scrollWidth / scrollWidthInScreen;
+ dy *= oe.scrollHeight / scrollHeightInScreen;
+
+ if (this.reverse) {
+ dx *= -1;
+ dy *= -1;
+ }
+
+ oe.setZoomPosition(oe.zoomX - dx, oe.zoomY - dy);
+
+ this.startX = oe.rawMouseX;
+ this.startY = oe.rawMouseY;
+ }
+};
+
+Neo.HandTool.prototype.rollOutHandler= function(oe) {};
+Neo.HandTool.prototype.upMoveHandler = function(oe) {}
+Neo.HandTool.prototype.rollOverHandler= function(oe) {}
+
+/*
+-------------------------------------------------------------------------
+ Slider(色やサイズのスライダを操作している時)
+-------------------------------------------------------------------------
+*/
+
+Neo.SliderTool = function() {};
+Neo.SliderTool.prototype = new Neo.ToolBase();
+Neo.SliderTool.prototype.type = Neo.Painter.TOOLTYPE_SLIDER;
+Neo.SliderTool.prototype.isUpMove = false;
+Neo.SliderTool.prototype.alt = false;
+
+Neo.SliderTool.prototype.downHandler = function(oe) {
+ if (!oe.isShiftDown) this.isDrag = true;
+
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+
+ var rect = this.target.getBoundingClientRect();
+ var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider'];
+ Neo.sliders[sliderType].downHandler(oe.rawMouseX - rect.left,
+ oe.rawMouseY - rect.top);
+};
+
+Neo.SliderTool.prototype.upHandler = function(oe) {
+ this.isDrag = false;
+ oe.popTool();
+
+ var rect = this.target.getBoundingClientRect();
+ var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider'];
+ Neo.sliders[sliderType].upHandler(oe.rawMouseX - rect.left,
+ oe.rawMouseY - rect.top);
+};
+
+Neo.SliderTool.prototype.moveHandler = function(oe) {
+ if (this.isDrag) {
+ var rect = this.target.getBoundingClientRect();
+ var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider'];
+ Neo.sliders[sliderType].moveHandler(oe.rawMouseX - rect.left,
+ oe.rawMouseY - rect.top);
+ }
+};
+
+Neo.SliderTool.prototype.upMoveHandler = function(oe) {}
+Neo.SliderTool.prototype.rollOutHandler= function(oe) {};
+Neo.SliderTool.prototype.rollOverHandler= function(oe) {}
+
+/*
+-------------------------------------------------------------------------
+ Fill(塗り潰し)
+-------------------------------------------------------------------------
+*/
+
+Neo.FillTool = function() {};
+Neo.FillTool.prototype = new Neo.ToolBase();
+Neo.FillTool.prototype.type = Neo.Painter.TOOLTYPE_FILL;
+Neo.FillTool.prototype.isUpMove = false;
+
+Neo.FillTool.prototype.downHandler = function(oe) {
+ var x = Math.floor(oe.mouseX);
+ var y = Math.floor(oe.mouseY);
+ oe._pushUndo();
+ oe.fill(x, y, oe.canvasCtx[oe.current]);
+};
+
+Neo.FillTool.prototype.upHandler = function(oe) {
+};
+
+Neo.FillTool.prototype.moveHandler = function(oe) {
+};
+
+Neo.FillTool.prototype.rollOutHandler= function(oe) {};
+Neo.FillTool.prototype.upMoveHandler = function(oe) {}
+Neo.FillTool.prototype.rollOverHandler= function(oe) {}
+
+
+/*
+-------------------------------------------------------------------------
+ EraseAll(全消し)
+-------------------------------------------------------------------------
+*/
+
+Neo.EraseAllTool = function() {};
+Neo.EraseAllTool.prototype = new Neo.ToolBase();
+Neo.EraseAllTool.prototype.type = Neo.Painter.TOOLTYPE_ERASEALL;
+Neo.EraseAllTool.prototype.isUpMove = false;
+
+Neo.EraseAllTool.prototype.downHandler = function(oe) {
+ oe._pushUndo();
+
+ oe.prepareDrawing();
+ oe.canvasCtx[oe.current].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+Neo.EraseAllTool.prototype.upHandler = function(oe) {
+};
+
+Neo.EraseAllTool.prototype.moveHandler = function(oe) {
+};
+
+Neo.EraseAllTool.prototype.rollOutHandler= function(oe) {};
+Neo.EraseAllTool.prototype.upMoveHandler = function(oe) {};
+Neo.EraseAllTool.prototype.rollOverHandler= function(oe) {};
+
+
+/*
+-------------------------------------------------------------------------
+ EffectToolBase(エフェックトツールのベースクラス)
+-------------------------------------------------------------------------
+*/
+
+Neo.EffectToolBase = function() {};
+Neo.EffectToolBase.prototype = new Neo.ToolBase();
+Neo.EffectToolBase.prototype.isUpMove = false;
+
+Neo.EffectToolBase.prototype.downHandler = function(oe) {
+ this.isUpMove = false;
+
+ this.startX = this.endX = oe.clipMouseX;
+ this.startY = this.endY = oe.clipMouseY;
+};
+
+Neo.EffectToolBase.prototype.upHandler = function(oe) {
+ if (this.isUpMove) return;
+ this.isUpMove = true;
+
+ this.startX = Math.floor(this.startX);
+ this.startY = Math.floor(this.startY);
+ this.endX = Math.floor(this.endX);
+ this.endY = Math.floor(this.endY);
+
+ var x = (this.startX < this.endX) ? this.startX : this.endX;
+ var y = (this.startY < this.endY) ? this.startY : this.endY;
+ var width = Math.abs(this.startX - this.endX) + 1;
+ var height = Math.abs(this.startY - this.endY) + 1;
+ var ctx = oe.canvasCtx[oe.current];
+
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (x + width > oe.canvasWidth) width = oe.canvasWidth - x;
+ if (y + height > oe.canvasHeight) height = oe.canvasHeight - y;
+
+ if (width > 0 && height > 0) {
+ oe._pushUndo();
+ oe.prepareDrawing();
+ this.doEffect(oe, x, y, width, height);
+ }
+
+ if (oe.tool.type != Neo.Painter.TOOLTYPE_PASTE) {
+ oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+Neo.EffectToolBase.prototype.moveHandler = function(oe) {
+ this.endX = oe.clipMouseX;
+ this.endY = oe.clipMouseY;
+
+ oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ this.drawCursor(oe);
+};
+
+Neo.EffectToolBase.prototype.rollOutHandler= function(oe) {};
+Neo.EffectToolBase.prototype.upMoveHandler = function(oe) {};
+Neo.EffectToolBase.prototype.rollOverHandler= function(oe) {};
+
+Neo.EffectToolBase.prototype.drawCursor = function(oe) {
+ var ctx = oe.destCanvasCtx;
+
+ ctx.save();
+ this.transformForZoom(oe);
+
+ var start = oe.getDestCanvasPosition(this.startX, this.startY, true);
+ var end = oe.getDestCanvasPosition(this.endX, this.endY, true);
+
+ var x = (start.x < end.x) ? start.x : end.x;
+ var y = (start.y < end.y) ? start.y : end.y;
+ var width = Math.abs(start.x - end.x) + oe.zoom;
+ var height = Math.abs(start.y - end.y) + oe.zoom;
+
+ if (this.isEllipse) {
+ oe.drawXOREllipse(ctx, x, y, width, height, this.isFill);
+
+ } else {
+ oe.drawXORRect(ctx, x, y, width, height, this.isFill);
+ }
+ ctx.restore();
+};
+
+Neo.EffectToolBase.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = this.defaultAlpha || 1.0;
+ Neo.updateUI();
+ };
+};
+
+/*
+-------------------------------------------------------------------------
+ EraseRect(消し四角)
+-------------------------------------------------------------------------
+*/
+
+Neo.EraseRectTool = function() {};
+Neo.EraseRectTool.prototype = new Neo.EffectToolBase();
+Neo.EraseRectTool.prototype.type = Neo.Painter.TOOLTYPE_ERASERECT;
+
+Neo.EraseRectTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.eraseRect(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ FlipH(左右反転)
+-------------------------------------------------------------------------
+*/
+
+Neo.FlipHTool = function() {};
+Neo.FlipHTool.prototype = new Neo.EffectToolBase();
+Neo.FlipHTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_H;
+
+Neo.FlipHTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.flipH(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ FlipV(上下反転)
+-------------------------------------------------------------------------
+*/
+
+Neo.FlipVTool = function() {};
+Neo.FlipVTool.prototype = new Neo.EffectToolBase();
+Neo.FlipVTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_V;
+
+Neo.FlipVTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.flipV(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ DodgeRect(角取り)
+-------------------------------------------------------------------------
+*/
+
+Neo.BlurRectTool = function() {};
+Neo.BlurRectTool.prototype = new Neo.EffectToolBase();
+Neo.BlurRectTool.prototype.type = Neo.Painter.TOOLTYPE_BLURRECT;
+
+Neo.BlurRectTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.blurRect(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+Neo.BlurRectTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 0.5;
+ Neo.updateUI();
+ };
+}
+
+/*
+-------------------------------------------------------------------------
+ Turn(傾け)
+-------------------------------------------------------------------------
+*/
+
+Neo.TurnTool = function() {};
+Neo.TurnTool.prototype = new Neo.EffectToolBase();
+Neo.TurnTool.prototype.type = Neo.Painter.TOOLTYPE_TURN;
+
+Neo.TurnTool.prototype.upHandler = function(oe) {
+ this.isUpMove = true;
+
+ this.startX = Math.floor(this.startX);
+ this.startY = Math.floor(this.startY);
+ this.endX = Math.floor(this.endX);
+ this.endY = Math.floor(this.endY);
+
+ var x = (this.startX < this.endX) ? this.startX : this.endX;
+ var y = (this.startY < this.endY) ? this.startY : this.endY;
+ var width = Math.abs(this.startX - this.endX) + 1;
+ var height = Math.abs(this.startY - this.endY) + 1;
+
+ if (width > 0 && height > 0) {
+ oe._pushUndo();
+ oe.turn(x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ Merge(レイヤー結合)
+-------------------------------------------------------------------------
+*/
+
+Neo.MergeTool = function() {};
+Neo.MergeTool.prototype = new Neo.EffectToolBase();
+Neo.MergeTool.prototype.type = Neo.Painter.TOOLTYPE_MERGE;
+
+Neo.MergeTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.merge(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ Copy(コピー)
+-------------------------------------------------------------------------
+*/
+
+Neo.CopyTool = function() {};
+Neo.CopyTool.prototype = new Neo.EffectToolBase();
+Neo.CopyTool.prototype.type = Neo.Painter.TOOLTYPE_COPY;
+
+Neo.CopyTool.prototype.doEffect = function(oe, x, y, width, height) {
+ oe.copy(x, y, width, height);
+ oe.setToolByType(Neo.Painter.TOOLTYPE_PASTE);
+ oe.tool.x = x;
+ oe.tool.y = y;
+ oe.tool.width = width;
+ oe.tool.height = height;
+};
+
+/*
+-------------------------------------------------------------------------
+ Paste(ペースト)
+-------------------------------------------------------------------------
+*/
+
+Neo.PasteTool = function() {};
+Neo.PasteTool.prototype = new Neo.ToolBase();
+Neo.PasteTool.prototype.type = Neo.Painter.TOOLTYPE_PASTE;
+
+Neo.PasteTool.prototype.downHandler = function(oe) {
+ this.startX = oe.mouseX;
+ this.startY = oe.mouseY;
+ this.drawCursor(oe);
+};
+
+Neo.PasteTool.prototype.upHandler = function(oe) {
+ oe._pushUndo();
+
+ oe.paste(this.x, this.y, this.width, this.height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+
+ oe.setToolByType(Neo.Painter.TOOLTYPE_COPY);
+};
+
+Neo.PasteTool.prototype.moveHandler = function(oe) {
+ var dx = Math.floor(oe.mouseX - this.startX);
+ var dy = Math.floor(oe.mouseY - this.startY);
+ oe.tempX = dx;
+ oe.tempY = dy;
+
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+// this.drawCursor(oe);
+};
+
+Neo.PasteTool.prototype.keyDownHandler = function(e) {
+ if (e.keyCode == 27) { //Escでキャンセル
+ var oe = Neo.painter;
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ oe.setToolByType(Neo.Painter.TOOLTYPE_COPY);
+ }
+};
+
+Neo.PasteTool.prototype.drawCursor = function(oe) {
+ var ctx = oe.destCanvasCtx;
+
+ ctx.save();
+ this.transformForZoom(oe);
+
+ var start = oe.getDestCanvasPosition(this.x, this.y, true);
+ var end = oe.getDestCanvasPosition(this.x + this.width, this.y + this.height, true);
+
+ var x = start.x + oe.tempX * oe.zoom;
+ var y = start.y + oe.tempY * oe.zoom;
+ var width = Math.abs(start.x - end.x);
+ var height = Math.abs(start.y - end.y);
+ oe.drawXORRect(ctx, x, y, width, height);
+ ctx.restore();
+};
+
+/*
+-------------------------------------------------------------------------
+ Rect(線四角)
+-------------------------------------------------------------------------
+*/
+
+Neo.RectTool = function() {};
+Neo.RectTool.prototype = new Neo.EffectToolBase();
+Neo.RectTool.prototype.type = Neo.Painter.TOOLTYPE_RECT;
+
+Neo.RectTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.rectMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ RectFill(四角)
+-------------------------------------------------------------------------
+*/
+
+Neo.RectFillTool = function() {};
+Neo.RectFillTool.prototype = new Neo.EffectToolBase();
+Neo.RectFillTool.prototype.type = Neo.Painter.TOOLTYPE_RECTFILL;
+
+Neo.RectFillTool.prototype.isFill = true;
+Neo.RectFillTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.rectFillMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ Ellipse(線楕円)
+-------------------------------------------------------------------------
+*/
+
+Neo.EllipseTool = function() {};
+Neo.EllipseTool.prototype = new Neo.EffectToolBase();
+Neo.EllipseTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSE;
+Neo.EllipseTool.prototype.isEllipse = true;
+Neo.EllipseTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.ellipseMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ EllipseFill(楕円)
+-------------------------------------------------------------------------
+*/
+
+Neo.EllipseFillTool = function() {};
+Neo.EllipseFillTool.prototype = new Neo.EffectToolBase();
+Neo.EllipseFillTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSEFILL;
+Neo.EllipseFillTool.prototype.isEllipse = true;
+Neo.EllipseFillTool.prototype.isFill = true;
+Neo.EllipseFillTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.ellipseFillMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+-------------------------------------------------------------------------
+ Text(テキスト)
+-------------------------------------------------------------------------
+*/
+
+Neo.TextTool = function() {};
+Neo.TextTool.prototype = new Neo.ToolBase();
+Neo.TextTool.prototype.type = Neo.Painter.TOOLTYPE_TEXT;
+Neo.TextTool.prototype.isUpMove = false;
+
+Neo.TextTool.prototype.downHandler = function(oe) {
+ this.startX = oe.mouseX;
+ this.startY = oe.mouseY;
+
+ if (Neo.painter.inputText) {
+ Neo.painter.updateInputText();
+
+ var rect = oe.container.getBoundingClientRect();
+ var text = Neo.painter.inputText;
+ var x = oe.rawMouseX - rect.left - 5;
+ var y = oe.rawMouseY - rect.top - 5;
+
+ text.style.left = x + "px";
+ text.style.top = y + "px";
+ text.style.display = "block";
+ text.focus();
+ }
+};
+
+Neo.TextTool.prototype.upHandler = function(oe) {
+};
+
+Neo.TextTool.prototype.moveHandler = function(oe) {};
+Neo.TextTool.prototype.upMoveHandler = function(oe) {};
+Neo.TextTool.prototype.rollOverHandler= function(oe) {};
+Neo.TextTool.prototype.rollOutHandler= function(oe) {};
+
+Neo.TextTool.prototype.keyDownHandler = function(e) {
+ if (e.keyCode == 13) { // Returnで確定
+ e.preventDefault();
+
+ var oe = Neo.painter;
+ var text = oe.inputText;
+ if (text) {
+ oe._pushUndo();
+ this.drawText(oe);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+
+ text.style.display = "none";
+ text.blur();
+ }
+ }
+};
+
+Neo.TextTool.prototype.kill = function(oe) {
+ Neo.painter.hideInputText();
+};
+
+Neo.TextTool.prototype.drawText = function(oe) {
+ var text = oe.inputText;
+
+ // unescape entities
+ //var tmp = document.createElement("textarea");
+ //tmp.innerHTML = text.innerHTML;
+ //var string = tmp.value;
+
+ var string = text.textContent || text.innerText;
+
+ if (string.length <= 0) return;
+ oe.doText(this.startX, this.startY, string, text.style.fontSize);
+};
+
+Neo.TextTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 1.0;
+ Neo.updateUI();
+ };
+};
+
+/*
+-------------------------------------------------------------------------
+ Dummy(何もしない時)
+-------------------------------------------------------------------------
+*/
+
+Neo.DummyTool = function() {};
+Neo.DummyTool.prototype = new Neo.ToolBase();
+Neo.DummyTool.prototype.type = Neo.Painter.TOOLTYPE_NONE;
+Neo.DummyTool.prototype.isUpMove = false;
+
+Neo.DummyTool.prototype.downHandler = function(oe) {
+};
+
+Neo.DummyTool.prototype.upHandler = function(oe) {
+ oe.popTool();
+};
+
+Neo.DummyTool.prototype.moveHandler = function(oe) {};
+Neo.DummyTool.prototype.upMoveHandler = function(oe) {}
+Neo.DummyTool.prototype.rollOverHandler= function(oe) {}
+Neo.DummyTool.prototype.rollOutHandler= function(oe) {}
+
+'use strict';
+
+Neo.CommandBase = function() {
+};
+Neo.CommandBase.prototype.data;
+Neo.CommandBase.prototype.execute = function() {}
+
+
+/*
+---------------------------------------------------
+ ZOOM
+---------------------------------------------------
+*/
+Neo.ZoomPlusCommand = function(data) {this.data = data};
+Neo.ZoomPlusCommand.prototype = new Neo.CommandBase();
+Neo.ZoomPlusCommand.prototype.execute = function() {
+ if (this.data.zoom < 12) {
+ this.data.setZoom(this.data.zoom + 1);
+ }
+ Neo.resizeCanvas();
+ Neo.painter.updateDestCanvas();
+};
+
+Neo.ZoomMinusCommand = function(data) {this.data = data};
+Neo.ZoomMinusCommand.prototype = new Neo.CommandBase();
+Neo.ZoomMinusCommand.prototype.execute = function() {
+ if (this.data.zoom >= 2) {
+ this.data.setZoom(this.data.zoom - 1);
+ }
+ Neo.resizeCanvas();
+ Neo.painter.updateDestCanvas();
+};
+
+/*
+---------------------------------------------------
+ UNDO
+---------------------------------------------------
+*/
+Neo.UndoCommand = function(data) {this.data = data};
+Neo.UndoCommand.prototype = new Neo.CommandBase();
+Neo.UndoCommand.prototype.execute = function() {
+ this.data.undo();
+};
+
+Neo.RedoCommand = function(data) {this.data = data};
+Neo.RedoCommand.prototype = new Neo.CommandBase();
+Neo.RedoCommand.prototype.execute = function() {
+ this.data.redo();
+};
+
+
+/*
+---------------------------------------------------
+---------------------------------------------------
+*/
+
+
+
+Neo.WindowCommand = function(data) {this.data = data};
+Neo.WindowCommand.prototype = new Neo.CommandBase();
+Neo.WindowCommand.prototype.execute = function() {
+ if (Neo.fullScreen) {
+ //if (confirm("¿Vista página?")) {
+ Neo.fullScreen = false;
+ Neo.updateWindow();
+ //}
+ } else {
+ //if (confirm("¿Vista ventana?")) {
+ Neo.fullScreen = true;
+ Neo.updateWindow();
+ //}
+ }
+};
+
+Neo.SubmitCommand = function(data) {this.data = data};
+Neo.SubmitCommand.prototype = new Neo.CommandBase();
+Neo.SubmitCommand.prototype.execute = function() {
+ var board = location.href.replace(/[^/]*$/, '');
+ console.log("submit: " + board);
+ this.data.submit(board);
+};
+
+Neo.CopyrightCommand = function(data) {this.data = data};
+Neo.CopyrightCommand.prototype = new Neo.CommandBase();
+Neo.CopyrightCommand.prototype.execute = function() {
+// var url = "http://hp.vector.co.jp/authors/VA016309/";
+// if (confirm(url + "\nしぃちゃんのホームページを表示しますか?")) {
+ var url = "http://github.com/funige/neo/";
+ if (confirm("PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?" + "\n")) {
+ Neo.openURL(url);
+ }
+};
+
+'use strict';
+
+/*
+-------------------------------------------------------------------------
+ Button
+-------------------------------------------------------------------------
+*/
+
+Neo.Button = function() {};
+Neo.Button.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.selected = false;
+ this.isMouseDown = false;
+
+ var ref = this;
+ if (window.PointerEvent) {
+ this.element.onpointerdown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onpointerup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onpointerover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onpointerout = function(e) { ref._mouseOutHandler(e); }
+
+ } else {
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onmouseup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onmouseover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onmouseout = function(e) { ref._mouseOutHandler(e); }
+ }
+ this.element.className = (!this.params.type == 'fill') ? "button" : "buttonOff";
+
+ return this;
+};
+
+Neo.Button.prototype._mouseDownHandler = function(e) {
+ if (Neo.painter.isUIPaused()) return;
+ this.isMouseDown = true;
+
+ if ((this.params.type == "fill") && (this.selected == false)) {
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ toolTip.setSelected((this.selected) ? false : true);
+ }
+ Neo.painter.setToolByType(Neo.Painter.TOOLTYPE_FILL);
+ }
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+Neo.Button.prototype._mouseUpHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+
+ if (this.onmouseup) this.onmouseup(this);
+ }
+};
+Neo.Button.prototype._mouseOutHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseout) this.onmouseout(this);
+ }
+};
+Neo.Button.prototype._mouseOverHandler = function(e) {
+ if (this.onmouseover) this.onmouseover(this);
+};
+
+Neo.Button.prototype.setSelected = function(selected) {
+ if (selected) {
+ this.element.className = "buttonOn";
+ } else {
+ this.element.className = "buttonOff";
+ }
+ this.selected = selected;
+};
+
+Neo.Button.prototype.update = function() {
+};
+
+/*
+-------------------------------------------------------------------------
+ ColorTip
+-------------------------------------------------------------------------
+*/
+
+Neo.colorTips = [];
+
+Neo.ColorTip = function() {};
+Neo.ColorTip.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+
+ this.selected = (this.name == "color1") ? true : false;
+ this.isMouseDown = false;
+
+ var ref = this;
+ if (window.PointerEvent) {
+ this.element.onpointerdown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onpointerup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onpointerover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onpointerout = function(e) { ref._mouseOutHandler(e); }
+
+ } else {
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onmouseup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onmouseover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onmouseout = function(e) { ref._mouseOutHandler(e); }
+ }
+ this.element.className = "colorTipOff";
+
+ var index = parseInt(this.name.slice(5)) - 1;
+ this.element.style.left = (index % 2) ? "0px" : "26px";
+ this.element.style.top = Math.floor(index / 2) * 21 + "px";
+
+ // base64 ColorTip.png
+ this.element.innerHTML = "<img style='max-width:44px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAASCAYAAAAg9DzcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANklEQVRIx+3OAQkAMADDsO3+Pe8qCj+0Akq6bQFqS2wTCpwE+R4IiyVYsGDBggULfirBgn8HX7BzCRwDx1QeAAAAAElFTkSuQmCC' />"
+
+ this.setColor(Neo.config.colors[params.index - 1]);
+
+ this.setSelected(this.selected);
+ Neo.colorTips.push(this);
+};
+
+Neo.ColorTip.prototype._mouseDownHandler = function(e) {
+ if (Neo.painter.isUIPaused()) return;
+ this.isMouseDown = true;
+
+ for (var i = 0; i < Neo.colorTips.length; i++) {
+ var colorTip = Neo.colorTips[i];
+ if (this == colorTip) {
+ if (e.shiftKey) {
+ this.setColor(Neo.config.colors[this.params.index - 1]);
+ } else if (e.button == 2 || e.ctrlKey || e.altKey) {
+ this.setColor(Neo.painter.foregroundColor);
+ }
+ }
+ colorTip.setSelected(this == colorTip) ? true : false;
+ }
+ Neo.painter.setColor(this.color);
+ Neo.updateUIColor(true, false);
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+Neo.ColorTip.prototype._mouseUpHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseup) this.onmouseup(this);
+ }
+};
+Neo.ColorTip.prototype._mouseOutHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseout) this.onmouseout(this);
+ }
+};
+Neo.ColorTip.prototype._mouseOverHandler = function(e) {
+ if (this.onmouseover) this.onmouseover(this);
+};
+
+Neo.ColorTip.prototype.setSelected = function(selected) {
+ if (selected) {
+ this.element.className = "colorTipOn";
+ } else {
+ this.element.className = "colorTipOff";
+ }
+ this.selected = selected;
+};
+
+Neo.ColorTip.prototype.setColor = function(color) {
+ this.color = color;
+ this.element.style.backgroundColor = color;
+};
+
+Neo.ColorTip.getCurrent = function() {
+ for (var i = 0; i < Neo.colorTips.length; i++) {
+ var colorTip = Neo.colorTips[i];
+ if (colorTip.selected) return colorTip;
+ }
+ return null;
+};
+
+/*
+-------------------------------------------------------------------------
+ ToolTip
+-------------------------------------------------------------------------
+*/
+
+Neo.toolTips = [];
+Neo.toolButtons = [];
+
+Neo.ToolTip = function() {};
+
+Neo.ToolTip.prototype.prevMode = -1;
+
+Neo.ToolTip.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.params.type = this.element.id;
+ this.name = name;
+ this.mode = 0;
+
+ this.isMouseDown = false;
+
+ var ref = this;
+ if (window.PointerEvent) {
+ this.element.onpointerdown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onpointerup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onpointerover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onpointerout = function(e) { ref._mouseOutHandler(e); }
+
+ } else {
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onmouseup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onmouseover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onmouseout = function(e) { ref._mouseOutHandler(e); }
+ }
+ this.selected = (this.params.type == "pen") ? true : false;
+ this.setSelected(this.selected);
+
+ this.element.innerHTML = "<canvas width=46 height=18></canvas><div class='label'></div>";
+ this.canvas = this.element.getElementsByTagName('canvas')[0];
+ this.label = this.element.getElementsByTagName('div')[0];
+
+ this.update();
+ return this;
+};
+
+Neo.ToolTip.prototype._mouseDownHandler = function(e) {
+ this.isMouseDown = true;
+
+ if (this.isTool) {
+ if (this.selected == false) {
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ toolTip.setSelected((this == toolTip) ? true : false);
+ }
+
+ } else {
+ var length = this.toolStrings.length;
+ if (e.button == 2 || e.ctrlKey || e.altKey) {
+ this.mode--;
+ if (this.mode < 0) this.mode = length - 1;
+ } else {
+ this.mode++;
+ if (this.mode >= length) this.mode = 0;
+ }
+ }
+ Neo.painter.setToolByType(this.tools[this.mode]);
+ this.update();
+ }
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+
+Neo.ToolTip.prototype._mouseUpHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseup) this.onmouseup(this);
+ }
+};
+
+Neo.ToolTip.prototype._mouseOutHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseout) this.onmouseout(this);
+ }
+};
+Neo.ToolTip.prototype._mouseOverHandler = function(e) {
+ if (this.onmouseover) this.onmouseover(this);
+};
+
+Neo.ToolTip.prototype.setSelected = function(selected) {
+ if (this.fixed) {
+ this.element.className = "toolTipFixed";
+
+ } else {
+ if (selected) {
+ this.element.className = "toolTipOn";
+ } else {
+ this.element.className = "toolTipOff";
+ }
+ }
+ this.selected = selected;
+};
+
+Neo.ToolTip.prototype.update = function() {};
+
+Neo.ToolTip.prototype.draw = function(c) {
+ if (this.hasTintImage) {
+ if (typeof c != "string") c = Neo.painter.getColorString(c);
+ var ctx = this.canvas.getContext("2d");
+
+ if (this.prevMode != this.mode) {
+ this.prevMode = this.mode;
+
+ var img = new Image();
+ img.src = this.toolIcons[this.mode];
+ img.onload = function() {
+ var ref = this;
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ this.drawTintImage(ctx, img, c, 0, 0);
+ }.bind(this);
+
+ } else {
+ this.tintImage(ctx, c);
+ }
+ }
+};
+
+Neo.ToolTip.prototype.drawTintImage = function(ctx, img, c, x, y) {
+ ctx.drawImage(img, x, y);
+ this.tintImage(ctx, c);
+};
+
+Neo.ToolTip.prototype.tintImage = function(ctx, c) {
+ c = (Neo.painter.getColor(c) & 0xffffff);
+
+ var imageData = ctx.getImageData(0, 0, 46, 18);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ for (var i = 0; i < buf32.length; i++) {
+ var a = buf32[i] & 0xff000000;
+ if (a) {
+ buf32[i] = buf32[i] & a | c;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+};
+
+Neo.ToolTip.bezier = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAT0lEQVRIx+3SQQoAIAhE0en+h7ZVEEKBZrX5b5sjKknAkRYpNslaMLPq44ZI9wwHs0vMQ/v87u0Kk8xfsaI242jbMdjPi5Y0r/zTAAAAD3UOjRf9jcO4sgAAAABJRU5ErkJggg==";
+Neo.ToolTip.blur = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAASUlEQVRIx+3VMQ4AIAgEQeD/f8bWWBnJYUh2SgtgK82G8/MhzVKwxOtTLgIUx6tDout4laiPIICA0Qj4bXxAy0+8LZP9yACAJwsqkggS55eiZgAAAABJRU5ErkJggg==";
+Neo.ToolTip.blurrect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAX0lEQVRIx+2XQQ4AEAwEt+I7/v+8Org6lJKt6NzLjjYE8DAKtLpYoDeCCCC7tYUd3ru2qQOzDTyndhJzB6KSAmxSgM0fAlGuzBnmlziqxB8jFJkUYJMCbAQYPxt2kF06fvYKgjPBO/IAAAAASUVORK5CYII=";
+Neo.ToolTip.brush = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQUlEQVRIx2NgGOKAEcb4z8CweRA4xpdUPSxofJ8BdP8WcjQxDaCDqQLQY4CsUBgFo2AUjIJRMApGwSgYBaNgZAIA0CoDwDbZu8oAAAAASUVORK5CYII=";
+Neo.ToolTip.burn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAPklEQVRIx+3PMRIAMAQAQbzM0/0sKZPeiDG57TQ4keH0Htx9VR+MCM1vOezl8xUsv4IAAkYjoBsB3QgAgL9tYXgF19rh9yoAAAAASUVORK5CYII=";
+Neo.ToolTip.copy = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XMQoAIAwDU/E7/v95Orh2KMUSC7m5Qs6AUqAxG1gzOLirwxhgmXOjOlg1oQY8sjf2mvYNSICNBNhIgE3oH/jlzfdo34AE2EiATXsBA+5mww6S5QASDwSGMt8ouwAAAABJRU5ErkJggg==";
+Neo.ToolTip.copy2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAN0lEQVRIx+3PwQkAIBADwdPKt3MtQVCOPNz5B7JV0pNxOwRW9zng+G92n+hmQJoBaQakGSBJf9tyBgQUV/fKCAAAAABJRU5ErkJggg==";
+Neo.ToolTip.ellipse = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAATklEQVRIx+2VMQ4AIAgD6/8fjbOJi1LFmt4OPQ0KIE7LNgggCBLbHkuFM9lM+Om+QwDjpksyb4tT86vlvzgEbYxefQPyv5D8HjDGGGOk6b3jJ+lYubd8AAAAAElFTkSuQmCC";
+Neo.ToolTip.ellipsefill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAVUlEQVRIx+2VURIAEAgFc/9D5waSHpV5+43ZHRMizRnRA1REARLHHq6NCFl01Nail+LeEDMgU34nYhlQQd6K+PsGKkSEZyArBPoK3Y6K/AOEEEJIayZHbhIKjkZrFwAAAABJRU5ErkJggg==";
+Neo.ToolTip.eraser = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAABQElEQVRIx+1WQY7CMAwcI37Cad+yXOgH4Gu8gAt9CtrDirfMHjZJbbcktVSpQnROSeMkY3vsFHhzSG3xfLpz/JVmG0mIqDkIMcc6+7Kejx6fdb0dq7w09rVFkrjejrMOunQ9vg7f/5QEIAd6E1Eo38WF8fF7n8sdALCrLerIzoFI4sI0Vtv1SYZ8CVbeF7tzF7JugIkVkxOauc6CIe8842S+XmMfsq7TN9LRTngZmTmVD4SrnzYaGYhFoxCWgajXuMjYGTuJ3dlwIBIN3U0cUVqLXCs5E7YeVsvAYJul5HWeLUhL3EpstQwooqoOTEHDOebpMn7ngkUsg3RotU8X1MkuVDrYohkIupC0YArX6T+PfX3kcbQLNV/iCKi6EB3xqXdAZ0JKthZ8B0QEl673NIEX/0I/z36Rf6ENGzZ8EP4A8Lp+9e9VWC4AAAAASUVORK5CYII=";
+Neo.ToolTip.flip = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAZklEQVRIx+2XQQoAIAgE1+g7/f95degWHSyTTXDOhTsSiUBgOtCq8mD3DiOA3NxTCVgKaLA0qHiFOsHSnC8ELKQAmxRgE15APQfWv9pzLjwX+CXsjvBPKAXYpACb8AICzM2GHeSWAfVOCIiJuQ9tAAAAAElFTkSuQmCC";
+Neo.ToolTip.freehand = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAdUlEQVRIx+2WUQrAMAhD3dj9r+y+VoSyLhYDynzQv1qiJlCR4hzeAhVRsiC3Jkj0c5hN7Lx7IQ9SphLE1ICdwko420purEWQuywN3pqxgcw2+WwAtU1GzoqiLZNwZBvMAIcO8y3YKUO8mkbmjPzjK9E0TUPjBoeyLAS0usjLAAAAAElFTkSuQmCC";
+Neo.ToolTip.line = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAU0lEQVRIx+2UQQ4AIAjD8P+PxivRGDQC47C+oN1hIgTLQAt4qIga2c23XYAVPkm3CVhlb4ShAa/rQgMi1i0NyFg3LaBq3bAA1LpfAd7/EkIIIR2YXFYSCpWS8w8AAAAASUVORK5CYII=";
+Neo.ToolTip.merge = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XQQrAQAgDx9Lv9JF9+e6h54IINlgyZ4UMOYgwmAXXmRxc3WECorJ3dAfrJtXAC7c6PPygAQuosYAaC6hJ3YHqlfyC8Q1YQI0F1IwXCHg+G3WQKhvwgwUFmFyYbwAAAABJRU5ErkJggg==";
+Neo.ToolTip.pen = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAK0lEQVRIx+3OsQkAMAwDQXn/oe3WfSAEctd9I5TA32pHJ/3AoTpfAQCAGwaa5AICJLKWSQAAAABJRU5ErkJggg==";
+Neo.ToolTip.rect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQElEQVRIx+3TMQ4AIAhD0WK8/5VxdcIYY8rw3wok7YAEr6iGKaU74BY0ro+6FKhyDHe4VxRwm6eFLn8AAADwwQIwTQgGo9ZMywAAAABJRU5ErkJggg==";
+Neo.ToolTip.rectfill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANElEQVRIx+3PIQ4AIBADwcL//3xYBMEgLiQztmab0GvcxkqqO3ALPbbO7rBXDnRzAADgYwvqDwIMJlGb5QAAAABJRU5ErkJggg==";
+Neo.ToolTip.text = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAcUlEQVRIx+2VwQ7AIAhDy7L//2V2WmIYg+ky2KEv8aCCqYQqQMgrJNpUQMXEKKDmAPHyspgSrBBvLZu3cQqZEdwhfusq0KdkVR5HlFfBvpI0mtIzeusFot7vFPqYuzZYMXUFlzc+qrIn7tf/ACGEkIwDlEQ94YZjzcgAAAAASUVORK5CYII=";
+Neo.ToolTip.tone = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAO0lEQVRIx+3PIQ4AMAgEwaP//zNVVZUELiQ7CgWstFy8IaVsPhT1Lb/T+fQEAtwIcCPAjQC39QEAgJIL6DQCFhAqsRkAAAAASUVORK5CYII=";
+
+/*
+-------------------------------------------------------------------------
+ PenTip
+-------------------------------------------------------------------------
+*/
+
+Neo.penTip;
+
+Neo.PenTip = function() {};
+Neo.PenTip.prototype = new Neo.ToolTip();
+
+Neo.PenTip.prototype.toolStrings = ["Lapiz", "Acuarela", "Texto"];
+Neo.PenTip.prototype.tools = [Neo.Painter.TOOLTYPE_PEN,
+ Neo.Painter.TOOLTYPE_BRUSH,
+ Neo.Painter.TOOLTYPE_TEXT];
+
+Neo.PenTip.prototype.hasTintImage = true;
+Neo.PenTip.prototype.toolIcons = [Neo.ToolTip.pen,
+ Neo.ToolTip.brush,
+ Neo.ToolTip.text];
+
+Neo.PenTip.prototype.init = function(name, params) {
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.PenTip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ this.draw(Neo.painter.foregroundColor);
+ if (this.label) {
+ this.label.innerHTML = this.toolStrings[this.mode];
+ }
+};
+
+/*
+-------------------------------------------------------------------------
+ Pen2Tip
+-------------------------------------------------------------------------
+*/
+
+Neo.pen2Tip;
+
+Neo.Pen2Tip = function() {};
+Neo.Pen2Tip.prototype = new Neo.ToolTip();
+
+Neo.Pen2Tip.prototype.toolStrings = ["Tono",
+ "Gradacion",
+ "Sobreexp.",
+ "Quemar"];
+Neo.Pen2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_TONE,
+ Neo.Painter.TOOLTYPE_BLUR,
+ Neo.Painter.TOOLTYPE_DODGE,
+ Neo.Painter.TOOLTYPE_BURN];
+
+Neo.Pen2Tip.prototype.hasTintImage = true;
+Neo.Pen2Tip.prototype.toolIcons = [Neo.ToolTip.tone,
+ Neo.ToolTip.blur,
+ Neo.ToolTip.burn,
+ Neo.ToolTip.burn];
+
+Neo.Pen2Tip.prototype.init = function(name, params) {
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.Pen2Tip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ switch (this.tools[this.mode]) {
+ case Neo.Painter.TOOLTYPE_TONE:
+ this.drawTone(Neo.painter.foregroundColor);
+ break;
+
+ case Neo.Painter.TOOLTYPE_DODGE:
+ this.draw(0xffc0c0c0);
+ break;
+
+ case Neo.Painter.TOOLTYPE_BURN:
+ this.draw(0xff404040);
+ break;
+
+ default:
+ this.draw(Neo.painter.foregroundColor);
+ break;
+ }
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+Neo.Pen2Tip.prototype.drawTone = function() {
+ var ctx = this.canvas.getContext("2d");
+
+ var imageData = ctx.getImageData(0, 0, 46, 18);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var c = Neo.painter.getColor() | 0xff000000;
+ var a = Math.floor(Neo.painter.alpha * 255);
+ var toneData = Neo.painter.getToneData(a);
+
+ for (var j = 0; j < 18; j++) {
+ for (var i = 0; i < 46; i++) {
+ if (j >= 1 && j < 12 &&
+ i >= 2 && i < 26 &&
+ toneData[(i%4) + (j%4) * 4]) {
+ buf32[j * 46 + i] = c;
+
+ } else {
+ buf32[j * 46 + i] = 0;
+ }
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+
+ this.prevMode = this.mode;
+};
+
+
+/*
+-------------------------------------------------------------------------
+ EraserTip
+-------------------------------------------------------------------------
+*/
+
+Neo.eraserTip;
+
+Neo.EraserTip = function() {};
+Neo.EraserTip.prototype = new Neo.ToolTip();
+
+Neo.EraserTip.prototype.toolStrings = ["Goma", "Goma", "Borrar"];
+Neo.EraserTip.prototype.tools = [Neo.Painter.TOOLTYPE_ERASER,
+ Neo.Painter.TOOLTYPE_ERASERECT,
+ Neo.Painter.TOOLTYPE_ERASEALL];
+
+Neo.EraserTip.prototype.init = function(name, params) {
+ this.drawOnce = false;
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.EraserTip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ if (this.drawOnce == false) {
+ this.draw();
+ this.drawOnce = true;
+ }
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+Neo.EraserTip.prototype.draw = function() {
+ var ctx = this.canvas.getContext("2d");
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ var img = new Image();
+
+ img.src = Neo.ToolTip.eraser;
+ img.onload = function() {
+ ctx.drawImage(img, 0, 0);
+ };
+};
+
+/*
+-------------------------------------------------------------------------
+ EffectTip
+-------------------------------------------------------------------------
+*/
+
+Neo.effectTip;
+
+Neo.EffectTip = function() {};
+Neo.EffectTip.prototype = new Neo.ToolTip();
+
+Neo.EffectTip.prototype.toolStrings = ["Cuadrado", "Cuadrado", "Circulo", "Circulo"];
+Neo.EffectTip.prototype.tools = [Neo.Painter.TOOLTYPE_RECTFILL,
+ Neo.Painter.TOOLTYPE_RECT,
+ Neo.Painter.TOOLTYPE_ELLIPSEFILL,
+ Neo.Painter.TOOLTYPE_ELLIPSE];
+
+Neo.EffectTip.prototype.hasTintImage = true;
+Neo.EffectTip.prototype.toolIcons = [Neo.ToolTip.rectfill,
+ Neo.ToolTip.rect,
+ Neo.ToolTip.ellipsefill,
+ Neo.ToolTip.ellipse];
+
+Neo.EffectTip.prototype.init = function(name, params) {
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.EffectTip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ this.draw(Neo.painter.foregroundColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+/*
+-------------------------------------------------------------------------
+ Effect2Tip
+-------------------------------------------------------------------------
+*/
+
+Neo.effect2Tip;
+
+Neo.Effect2Tip = function() {};
+Neo.Effect2Tip.prototype = new Neo.ToolTip();
+
+Neo.Effect2Tip.prototype.toolStrings = ["Copiar", "Unir",
+ "Cortar",
+ "Inv. Izq/Der", "Inv. Arr/Aba", "Inclinar"];
+Neo.Effect2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_COPY,
+ Neo.Painter.TOOLTYPE_MERGE,
+ Neo.Painter.TOOLTYPE_BLURRECT,
+ Neo.Painter.TOOLTYPE_FLIP_H,
+ Neo.Painter.TOOLTYPE_FLIP_V,
+ Neo.Painter.TOOLTYPE_TURN];
+
+Neo.Effect2Tip.prototype.hasTintImage = true;
+Neo.Effect2Tip.prototype.toolIcons = [Neo.ToolTip.copy,
+ Neo.ToolTip.merge,
+ Neo.ToolTip.blurrect,
+ Neo.ToolTip.flip,
+ Neo.ToolTip.flip,
+ Neo.ToolTip.flip];
+
+Neo.Effect2Tip.prototype.init = function(name, params) {
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+
+ this.img = document.createElement("img");
+ this.img.src = Neo.ToolTip.copy2;
+ this.element.appendChild(this.img);
+ return this;
+};
+
+Neo.Effect2Tip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ this.draw(Neo.painter.foregroundColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+/*
+-------------------------------------------------------------------------
+ MaskTip
+-------------------------------------------------------------------------
+*/
+
+Neo.maskTip;
+
+Neo.MaskTip = function() {};
+Neo.MaskTip.prototype = new Neo.ToolTip();
+
+Neo.MaskTip.prototype.toolStrings = ["Normal", "Masc.", "Masc. Inv.", "Adicion", "Substrac"];
+
+Neo.MaskTip.prototype.init = function(name, params) {
+ this.fixed = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.MaskTip.prototype._mouseDownHandler = function(e) {
+ this.isMouseDown = true;
+
+ if (e.button == 2 || e.ctrlKey || e.altKey) {
+ Neo.painter.maskColor = Neo.painter.foregroundColor;
+
+ } else {
+ var length = this.toolStrings.length;
+ this.mode++;
+ if (this.mode >= length) this.mode = 0;
+ Neo.painter.maskType = this.mode;
+ }
+ this.update();
+
+ if (this.onmousedown) this.onmousedown(this);
+}
+
+Neo.MaskTip.prototype.update = function() {
+ this.draw(Neo.painter.maskColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+Neo.MaskTip.prototype.draw = function(c) {
+ if (typeof c != "string") c = Neo.painter.getColorString(c);
+
+ var ctx = this.canvas.getContext("2d");
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ ctx.fillStyle = c;
+ ctx.fillRect(1, 1, 43, 9);
+};
+
+/*
+-------------------------------------------------------------------------
+ DrawTip
+-------------------------------------------------------------------------
+*/
+
+Neo.drawTip;
+
+Neo.DrawTip = function() {};
+Neo.DrawTip.prototype = new Neo.ToolTip();
+
+Neo.DrawTip.prototype.toolStrings = ["Libre", "Linea", "Curva"];
+
+Neo.DrawTip.prototype.hasTintImage = true;
+Neo.DrawTip.prototype.toolIcons = [Neo.ToolTip.freehand,
+ Neo.ToolTip.line,
+ Neo.ToolTip.bezier];
+
+Neo.DrawTip.prototype.init = function(name, params) {
+ this.fixed = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.DrawTip.prototype._mouseDownHandler = function(e) {
+ this.isMouseDown = true;
+
+ var length = this.toolStrings.length;
+ if (e.button == 2 || e.ctrlKey || e.altKey) {
+ this.mode--;
+ if (this.mode < 0) this.mode = length - 1;
+ } else {
+ this.mode++;
+ if (this.mode >= length) this.mode = 0;
+ }
+ Neo.painter.drawType = this.mode;
+ this.update();
+
+ if (this.onmousedown) this.onmousedown(this);
+}
+
+Neo.DrawTip.prototype.update = function() {
+ this.mode = Neo.painter.drawType;
+ this.draw(Neo.painter.foregroundColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+/*
+-------------------------------------------------------------------------
+ ColorSlider
+-------------------------------------------------------------------------
+*/
+
+Neo.sliders = [];
+
+Neo.ColorSlider = function() {};
+
+Neo.ColorSlider.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.isMouseDown = false;
+ this.value = 0;
+ this.type = this.params.type;
+
+ this.element.className = "colorSlider";
+ this.element.innerHTML = "<div class='slider'></div><div class='label'></div>";
+ this.element.innerHTML += "<div class='hit'></div>";
+
+ this.slider = this.element.getElementsByClassName('slider')[0];
+ this.label = this.element.getElementsByClassName('label')[0];
+ this.hit = this.element.getElementsByClassName('hit')[0];
+ this.hit['data-slider'] = params.type;
+
+ switch (this.type) {
+ case Neo.SLIDERTYPE_RED:
+ this.prefix = "R";
+ this.slider.style.backgroundColor = "#fa9696";
+ break;
+ case Neo.SLIDERTYPE_GREEN:
+ this.prefix = "G";
+ this.slider.style.backgroundColor = "#82f238";
+ break;
+ case Neo.SLIDERTYPE_BLUE:
+ this.prefix = "B";
+ this.slider.style.backgroundColor = "#8080ff";
+ break;
+ case Neo.SLIDERTYPE_ALPHA:
+ this.prefix = "A";
+ this.slider.style.backgroundColor = "#aaaaaa";
+ this.value = 255;
+ break;
+ }
+
+ this.update();
+ return this;
+};
+
+Neo.ColorSlider.prototype.downHandler = function(x, y) {
+ if (Neo.painter.isShiftDown) {
+ this.shift(x, y);
+
+ } else {
+ this.slide(x, y);
+ }
+};
+
+Neo.ColorSlider.prototype.moveHandler = function(x, y) {
+ this.slide(x, y);
+};
+
+Neo.ColorSlider.prototype.upHandler = function(x, y) {
+};
+
+Neo.ColorSlider.prototype.shift = function(x, y) {
+ var value;
+ if (x >= 0 && x < 60 && y >= 0 && y <= 15) {
+ var v = Math.floor((x - 5) * 5.0);
+ var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0;
+
+ value = Math.max(Math.min(v, 255), min);
+ if (this.value > value || this.value == 255) {
+ this.value--;
+ } else {
+ this.value++;
+ }
+ this.value = Math.max(Math.min(this.value, 255), min);
+ this.value0 = this.value;
+ this.x0 = x;
+ }
+
+ if (this.type == Neo.SLIDERTYPE_ALPHA) {
+ Neo.painter.alpha = this.value / 255.0;
+ this.update();
+ Neo.updateUIColor(false, false);
+
+ } else {
+ var r = Neo.sliders[Neo.SLIDERTYPE_RED].value;
+ var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value;
+ var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value;
+
+ Neo.painter.setColor(r<<16 | g<<8 | b);
+ Neo.updateUIColor(true, true);
+ }
+};
+
+Neo.ColorSlider.prototype.slide = function(x, y) {
+ var value;
+ if (x >= 0 && x < 60 && y >= 0 && y <= 15) {
+ var v = Math.floor((x - 5) * 5.0);
+ value = Math.round(v / 5) * 5;
+
+ this.value0 = value;
+ this.x0 = x;
+
+ } else {
+ var d = (x - this.x0) / 3.0;
+ value = this.value0 + d;
+ }
+
+ var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0;
+ this.value = Math.max(Math.min(value, 255), min);
+
+ if (this.type == Neo.SLIDERTYPE_ALPHA) {
+ Neo.painter.alpha = this.value / 255.0;
+ this.update();
+ Neo.updateUIColor(false, false);
+
+ } else {
+ var r = Neo.sliders[Neo.SLIDERTYPE_RED].value;
+ var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value;
+ var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value;
+
+ Neo.painter.setColor(r<<16 | g<<8 | b);
+// Neo.updateUIColor(true, true);
+ }
+};
+
+Neo.ColorSlider.prototype.update = function() {
+ var color = Neo.painter.getColor();
+ var alpha = Neo.painter.alpha * 255;
+
+ switch (this.type) {
+ case Neo.SLIDERTYPE_RED: this.value = (color & 0x0000ff); break;
+ case Neo.SLIDERTYPE_GREEN: this.value = (color & 0x00ff00) >> 8; break;
+ case Neo.SLIDERTYPE_BLUE: this.value = (color & 0xff0000) >> 16; break;
+ case Neo.SLIDERTYPE_ALPHA: this.value = alpha; break;
+ }
+
+ var width = this.value * 49.0 / 255.0;
+ width = Math.max(Math.min(48, width), 1);
+
+ this.slider.style.width = width.toFixed(2) + "px";
+ this.label.innerHTML = this.prefix + this.value.toFixed(0);
+};
+
+/*
+-------------------------------------------------------------------------
+ SizeSlider
+-------------------------------------------------------------------------
+*/
+
+Neo.SizeSlider = function() {};
+
+Neo.SizeSlider.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.isMouseDown = false;
+ this.value = this.value0 = 1;
+
+ this.element.className = "sizeSlider";
+ this.element.innerHTML = "<div class='slider'></div><div class='label'></div>";
+ this.element.innerHTML += "<div class='hit'></div>"
+
+ this.slider = this.element.getElementsByClassName('slider')[0];
+ this.label = this.element.getElementsByClassName('label')[0];
+ this.hit = this.element.getElementsByClassName('hit')[0];
+ this.hit['data-slider'] = params.type;
+
+ this.slider.style.backgroundColor = Neo.painter.foregroundColor;
+ this.update();
+ return this;
+};
+
+Neo.SizeSlider.prototype.downHandler = function(x, y) {
+ if (Neo.painter.isShiftDown) {
+ this.shift(x, y);
+
+ } else {
+ this.value0 = this.value;
+ this.y0 = y;
+ this.slide(x, y);
+ }
+};
+
+Neo.SizeSlider.prototype.moveHandler = function(x, y) {
+ this.slide(x, y);
+};
+
+Neo.SizeSlider.prototype.upHandler = function(x, y) {
+};
+
+Neo.SizeSlider.prototype.shift = function(x, y) {
+ var value0 = Neo.painter.lineWidth;
+ var value;
+
+ if (!Neo.painter.tool.alt) {
+ var v = Math.floor((y - 4) * 30.0 / 33.0);
+
+ value = Math.max(Math.min(v, 30), 1);
+ if (value0 > value || value0 == 30) {
+ value0--;
+ } else {
+ value0++;
+ }
+ this.setSize(value0);
+ }
+};
+
+Neo.SizeSlider.prototype.slide = function(x, y) {
+ var value;
+ if (!Neo.painter.tool.alt) {
+ if (x >= 0 && x < 48 && y >= 0 && y < 41) {
+ var v = Math.floor((y - 4) * 30.0 / 33.0);
+ value = v;
+
+ this.value0 = value;
+ this.y0 = y;
+
+ } else {
+ var d = (y - this.y0) / 7.0;
+ value = this.value0 + d;
+ }
+ } else {
+ // Ctrl+Alt+ドラッグでサイズ変更するとき
+ var d = y - this.y0;
+ value = this.value0 + d;
+ }
+
+ value = Math.max(Math.min(value, 30), 1);
+ this.setSize(value);
+};
+
+Neo.SizeSlider.prototype.setSize = function(value) {
+ value = Math.round(value);
+ Neo.painter.lineWidth = Math.max(Math.min(30, value), 1);
+
+ var tool = Neo.painter.getCurrentTool();
+ if (tool) {
+ if (tool.type == Neo.Painter.TOOLTYPE_BRUSH) {
+ Neo.painter.alpha = tool.getAlpha();
+ Neo.sliders[Neo.SLIDERTYPE_ALPHA].update();
+
+ } else if (tool.type == Neo.Painter.TOOLTYPE_TEXT) {
+ Neo.painter.updateInputText();
+ }
+ }
+ this.update();
+};
+
+Neo.SizeSlider.prototype.update = function() {
+ this.value = Neo.painter.lineWidth;
+
+ var height = this.value * 33.0 / 30.0;
+ height = Math.max(Math.min(34, height), 1);
+
+ this.slider.style.height = height.toFixed(2) + "px";
+ this.label.innerHTML = this.value + "px";
+ this.slider.style.backgroundColor = Neo.painter.foregroundColor;
+};
+
+/*
+-------------------------------------------------------------------------
+ LayerControl
+-------------------------------------------------------------------------
+*/
+
+Neo.LayerControl = function() {};
+Neo.LayerControl.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.isMouseDown = false;
+
+ var ref = this;
+
+ var mousedown = (window.PointerEvent) ? "onpointerdown" : "onmousedown";
+ this.element[mousedown] = function(e) { ref._mouseDownHandler(e); }
+ this.element.className = "layerControl";
+ this.element.innerHTML = "<div class='bg'></div><div class='label0'>Capa0</div><div class='label1'>Capa1</div><div class='line1'></div><div class='line0'></div>";
+
+ this.bg = this.element.getElementsByClassName('bg')[0];
+ this.label0 = this.element.getElementsByClassName('label0')[0];
+ this.label1 = this.element.getElementsByClassName('label1')[0];
+ this.line0 = this.element.getElementsByClassName('line0')[0];
+ this.line1 = this.element.getElementsByClassName('line1')[0];
+
+ this.line0.style.display = "none";
+ this.line1.style.display = "none";
+ this.label1.style.display = "none";
+
+ this.update();
+ return this;
+};
+
+Neo.LayerControl.prototype._mouseDownHandler = function(e) {
+ if (e.button == 2 || e.ctrlKey || e.altKey) {
+ var visible = Neo.painter.visible[Neo.painter.current];
+ Neo.painter.visible[Neo.painter.current] = (visible) ? false : true;
+
+ } else {
+ var current = Neo.painter.current;
+ Neo.painter.current = (current) ? 0 : 1
+ }
+ Neo.painter.updateDestCanvas(0, 0, Neo.painter.canvasWidth, Neo.painter.canvasHeight);
+ if (Neo.painter.tool.type == Neo.Painter.TOOLTYPE_PASTE) {
+ Neo.painter.tool.drawCursor(Neo.painter);
+ }
+ this.update();
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+
+Neo.LayerControl.prototype.update = function() {
+ this.label0.style.display = (Neo.painter.current == 0) ? "block" : "none";
+ this.label1.style.display = (Neo.painter.current == 1) ? "block" : "none";
+ this.line0.style.display = (Neo.painter.visible[0]) ? "none" : "block";
+ this.line1.style.display = (Neo.painter.visible[1]) ? "none" : "block";
+};
+
+/*
+-------------------------------------------------------------------------
+ ReserveControl
+-------------------------------------------------------------------------
+*/
+Neo.reserveControls = [];
+
+Neo.ReserveControl = function() {};
+Neo.ReserveControl.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+
+ var ref = this;
+
+ var mousedown = (window.PointerEvent) ? "onpointerdown" : "onmousedown";
+ this.element[mousedown] = function(e) { ref._mouseDownHandler(e); }
+ this.element.className = "reserve";
+
+ var index = parseInt(this.name.slice(7)) - 1;
+ this.element.style.top = "1px";
+ this.element.style.left = (index * 15 + 2) + "px";
+
+ this.reserve = Neo.clone(Neo.config.reserves[index]);
+ this.update();
+
+ Neo.reserveControls.push(this);
+ return this;
+};
+
+Neo.ReserveControl.prototype._mouseDownHandler = function(e) {
+ if (e.button == 2 || e.ctrlKey || e.altKey) {
+ this.save();
+ } else {
+ this.load();
+ }
+ this.update();
+};
+
+Neo.ReserveControl.prototype.load = function() {
+ Neo.painter.setToolByType(this.reserve.tool)
+ Neo.painter.foregroundColor = this.reserve.color;
+ Neo.painter.lineWidth = this.reserve.size;
+ Neo.painter.alpha = this.reserve.alpha;
+
+ switch (this.reserve.tool) {
+ case Neo.Painter.TOOLTYPE_PEN:
+ case Neo.Painter.TOOLTYPE_BRUSH:
+ case Neo.Painter.TOOLTYPE_TONE:
+ Neo.painter.drawType = this.reserve.drawType;
+ };
+ Neo.updateUI();
+};
+
+Neo.ReserveControl.prototype.save = function() {
+ this.reserve.color = Neo.painter.foregroundColor;
+ this.reserve.size = Neo.painter.lineWidth;
+ this.reserve.drawType = Neo.painter.drawType;
+ this.reserve.alpha = Neo.painter.alpha;
+ this.reserve.tool = Neo.painter.tool.getType();
+ this.element.style.backgroundColor = this.reserve.color;
+ this.update();
+ Neo.updateUI();
+};
+
+Neo.ReserveControl.prototype.update = function() {
+ this.element.style.backgroundColor = this.reserve.color;
+};
+
+/*
+-------------------------------------------------------------------------
+ ScrollBarButton
+-------------------------------------------------------------------------
+*/
+
+Neo.scrollH;
+Neo.scrollV;
+
+Neo.ScrollBarButton = function() {};
+Neo.ScrollBarButton.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+
+ this.element.innerHTML = "<div></div>";
+ this.barButton = this.element.getElementsByTagName("div")[0];
+ this.element['data-bar'] = true;
+ this.barButton['data-bar'] = true;
+
+ if (name == "scrollH") Neo.scrollH = this;
+ if (name == "scrollV") Neo.scrollV = this;
+ return this;
+};
+
+Neo.ScrollBarButton.prototype.update = function(oe) {
+ if (this.name == "scrollH") {
+ var a = oe.destCanvas.width / (oe.canvasWidth * oe.zoom);
+ var barWidth = Math.ceil(oe.destCanvas.width * a);
+ var barX = (oe.scrollBarX) * (oe.destCanvas.width - barWidth);
+ this.barButton.style.width = (Math.ceil(barWidth) - 4) + "px";
+ this.barButton.style.left = Math.floor(barX) + "px";
+
+ } else {
+ var a = oe.destCanvas.height / (oe.canvasHeight * oe.zoom);
+ var barHeight = Math.ceil(oe.destCanvas.height * a);
+ var barY = (oe.scrollBarY) * (oe.destCanvas.height - barHeight);
+ this.barButton.style.height = (Math.ceil(barHeight) - 4) + "px";
+ this.barButton.style.top = Math.floor(barY) + "px";
+ }
+};
+
diff --git a/static/js/paintbbs/PaintBBS-1.3.4.css b/static/js/paintbbs/PaintBBS-1.3.4.css
new file mode 100644
index 0000000..2e5b4f7
--- /dev/null
+++ b/static/js/paintbbs/PaintBBS-1.3.4.css
@@ -0,0 +1,547 @@
+.NEO {
+ margin:0;
+ line-height:18px;
+
+ user-select: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+
+ touch-callout: none;
+ -webkit-touch-callout: none;
+}
+
+.NEO *:active,
+.NEO *:hover {
+ cursor: default;
+}
+
+.NEO #container{
+ width: 100%;
+ height: 100%;
+ position: relative;
+ border: 1px dotted transparent;
+}
+
+.NEO #center{
+ display: table;
+ position: relative;
+ height: 100%;
+ margin: auto;
+}
+
+.NEO #toolsWrapper{
+ width: 52px;
+ display: table;
+ position:absolute;
+ top: 0;
+ right: -3px;
+}
+
+.NEO #tools{
+ width: 52px;
+ display: table-cell;
+ vertical-align: middle;
+ position: relative;
+}
+
+.NEO #painterContainer{
+ display:table-cell;
+ vertical-align: middle;
+ position: relative;
+}
+
+.NEO #painterWrapper{
+ padding: 0 55px 0 0;
+ position: relative;
+
+ float: right; /* なぜかChrome55でずれるので対策 */
+}
+
+.NEO #upper {
+ position: absolute;
+ right: 0;
+
+ height:30px;
+ padding-right: 75px; //20px;
+ text-align:right;
+}
+
+.NEO #lower {
+ height:30px;
+}
+
+.NEO #painter {
+ position: relative;
+ padding: 20px 20px 20px 20px;
+
+ margin-top: 30px;
+}
+
+.NEO #canvas {
+ position: relative;
+ width: 300px;
+ height: 300px;
+ background-color: white;
+}
+
+.NEO #headerButtons {
+ position: absolute;
+ top: 5px;
+ left: 5px;
+}
+
+.NEO #footerButtons {
+ position: absolute;
+ bottom: 5px;
+ left: 5px;
+}
+
+.NEO #window { float: left; }
+
+/*
+-----------------------
+ Modal Window
+-----------------------
+*/
+
+.NEO #pageView{
+ background-color: white;
+}
+
+.NEO #windowView{
+ z-index: 9999;
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: white;
+}
+
+/*
+-----------------------
+ Controls
+-----------------------
+*/
+
+.NEO #zoomMinus {
+ padding: 0;
+ margin: 0;
+ width:16px;
+ height:16px;
+ margin-left:1px;
+}
+
+.NEO #zoomPlus {
+ padding: 0;
+ margin: 0;
+ width:16px;
+ height:16px;
+}
+
+.NEO #zoomMinusWrapper {
+ position: absolute;
+ right: -20px;
+ bottom: -21px;
+ width: 19px;
+ height: 19px;
+ text-align:center;
+}
+
+.NEO #zoomPlusWrapper {
+ position: absolute;
+ left: -21px;
+ bottom: -21px;
+ width: 19px;
+ height: 19px;
+ text-overflow: hidden;
+ text-align:center;
+}
+
+.NEO #scrollH {
+ position: absolute;
+ left: 1px;
+ bottom: -20px;
+ width: calc(100% - 2px);
+ height: 18px;
+}
+
+.NEO #scrollV {
+ position: absolute;
+ right: -20px;
+ top: 1px;
+ width: 18px;
+ height: calc(100% - 2px);
+}
+
+.NEO #scrollH div {
+ position: absolute;
+ width: 50px;
+ height: 16px;
+}
+
+.NEO #scrollV div {
+ position: absolute;
+ width: 16px;
+ height: 50px;
+}
+
+.NEO #scrollH div:hover {}
+.NEO #scrollV div:hover {}
+
+.NEO #neoWarning {
+ position: absolute;
+ left: 5px;
+ top: 5px;
+ color: red;
+ pointer-events: none;
+ text-align: left;
+ transition: all 2s;
+}
+
+/*
+-----------------------
+ Widgets
+-----------------------
+*/
+
+.NEO .buttonOff {
+ display: inline-block;
+ border: 1px solid white;
+ height: 19px;
+ padding: 3px;
+ height: 16px;
+ font-size: 15px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ margin-right: 4px;
+
+ border-left: 1px solid rgba(0, 0, 0, 0);
+ border-top: 1px solid rgba(0, 0, 0, 0);
+ border-right: 1px solid rgba(0, 0, 0, 0);
+ border-bottom: 1px solid rgba(0, 0, 0, 0);
+
+ -webkit-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+ margin: 1px;
+
+}
+
+.NEO .buttonOff:hover {}
+
+.NEO .buttonOff:active,
+.NEO .buttonOn {
+ display: inline-block;
+ height: 19px;
+ padding: 3px;
+ height: 16px;
+ font-size: 15px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ margin-right: 4px;
+
+ border-right: 1px solid rgba(0, 0, 0, 0);
+ border-bottom: 1px solid rgba(0, 0, 0, 0);
+
+ -webkit-font-smoothing: antialiased;
+ font-smoothing: antialiased;
+ margin: 1px;
+}
+
+.NEO #right { display: inline-block; float: right; margin-left: 10px; }
+
+.NEO .toolTipOff,
+.NEO .toolTipFixed {
+ position:relative;
+ padding: 0;
+ margin: 0;
+ margin-top: 3px;
+ margin-bottom: 3px;
+
+ width: 46px;
+ height: 18px;
+ border-top: 1px solid #ffffff;
+ border-left: 1px solid #ffffff;
+ border-right: 1px solid #9397b2;
+ border-bottom: 1px solid #9397b2;
+}
+
+.NEO .toolTipOn {
+ position:relative;
+ padding: 0;
+ margin: 0;
+ margin-top: 3px;
+ margin-bottom: 3px;
+
+ width: 46px;
+ height: 18px;
+ border-top: 1px solid rgba(0, 0, 0, 0);
+ border-left: 1px solid rgba(0, 0, 0, 0);
+ border-right: 1px solid #ffffff;
+ border-bottom: 1px solid #ffffff;
+}
+
+
+
+.NEO .toolTipOff canvas,
+.NEO .toolTipOn canvas,
+.NEO .toolTipFixed canvas {
+ position: absolute;
+ top: 0;
+ left: 0;
+}
+
+.NEO .toolTipOff .label,
+.NEO .toolTipOn .label,
+.NEO .toolTipFixed .label {
+ position: absolute;
+ bottom: -4px;
+ left: 1px;
+ font-size:12px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: -1px;
+ overflow: hidden !important;
+}
+
+.NEO .colorTips {
+ position:relative;
+ width: 48px;
+ height: 144px;
+ padding: 0;
+ margin: 0;
+ margin-top: 4px;
+ margin-left: 0px;
+}
+
+.NEO .colorTipOff {
+ position: absolute;
+ overflow: hidden;
+ width: 22px;
+ height: 18px;
+ margin: -1px 4px 0px 0px;
+ padding: 0;
+}
+
+.NEO .colorTipOff img {
+ left: 0;
+ opacity: 0.5;
+ position: absolute;
+ pointer-events:none;
+}
+
+.NEO .colorTipOn {
+ position: absolute;
+ overflow: hidden;
+ width: 22px;
+ height: 18px;
+ margin: -1px 4px 0px 0px;
+ padding: 0;
+}
+
+.NEO .colorTipOn img {
+ left: -22px;
+ opacity: 0.5;
+ position: absolute;
+ pointer-events:none;
+}
+
+.NEO .colorSlider {
+ width: 48px;
+ height:13px;
+ position: relative;
+ margin-top: 3px;
+}
+
+.NEO .colorSlider .label {
+ pointer-events: none;
+ position: absolute;
+ left: 2px;
+ bottom: -3px;
+ font-size:12px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: middle;
+}
+
+.NEO .colorSlider .slider {
+ position: absolute;
+ height: 100%;
+ left: 0px;
+ width: 50%;
+ background-color: #fa9696;
+ box-shadow: -1px 0 0 0px rgba(0, 0, 0, 0.3) inset;
+}
+
+.NEO .colorSlider .hit {
+ position:absolute;
+ width: 60px;
+ height: 13px;
+ left: -6px;
+ background-color: white;
+ opacity: 0.01;
+}
+
+.NEO .sizeSlider {
+ width: 48px;
+ height:33px;
+ position: relative;
+ margin-top: 4px;
+}
+
+.NEO .sizeSlider .label {
+ pointer-events: none;
+ position: absolute;
+ left: 2px;
+ bottom: -3px;
+ font-size:12px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: middle;
+}
+
+.NEO .sizeSlider .slider {
+ position: absolute;
+ width: 100%;
+ top: 0px;
+ height: 33%;
+ background-color: #82f238;
+ box-shadow: 0 -1px 0 0px rgba(0, 0, 0, 0.3) inset;
+}
+
+.NEO .sizeSlider .hit {
+ position:absolute;
+ width: 48px;
+ height: 41px;
+ top: -4px;
+ background-color: white;
+ opacity: 0.01;
+}
+
+.NEO .reserveControl {
+ width: 48px;
+ height: 13px;
+ position: relative;
+}
+
+.NEO .reserveControl .reserve {
+ position: absolute;
+ width: 11px;
+ height: 8px;
+ background-color: white;
+}
+
+.NEO .layerControl {
+ width: 48px;
+ height: 20px;
+ position: relative;
+ margin-top: 6px;
+}
+
+.NEO .layerControl .bg {
+ position: absolute;
+ width: 44px;
+ height: 9px;
+ margin: 0;
+
+ top: 0px;
+ left: 2px;
+}
+
+.NEO .layerControl .line1 {
+ position: absolute;
+ width: 50px;
+ height:10px;
+ margin: 0;
+ padding: 0;
+
+ top: 0px;
+ left: -1px;
+ background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent);
+}
+
+.NEO .layerControl .line0 {
+ position: absolute;
+ width: 50px;
+ height: 10px;
+ margin: 0;
+ padding: 0;
+
+ top: 10px;
+ left: -1px;
+ background-image: linear-gradient(to top right, transparent, transparent 47%, red 47%, red 53%, transparent 53%, transparent);
+}
+
+.NEO .layerControl .label1 {
+ position: absolute;
+ left: 2px;
+ Top: -4px;
+ font-size:11px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: baseline;
+}
+
+.NEO .layerControl .label0 {
+ position: absolute;
+ left: 2px;
+ Top: 6px;
+ font-size:11px;
+ font-weight: 100;
+ font-family: 'Arial';
+ letter-spacing: 0;
+ vertical-align: baseline;
+}
+
+/*
+-----------------------
+ InputText
+-----------------------
+*/
+
+.NEO .inputText {
+ z-index: 100000;
+ position: absolute;
+
+ text-align: left;
+ white-space: nowrap;
+ color: #0000ff;
+
+ font-family: 'Arial';
+ padding: 1px 5px 1px 5px;
+ font-size: 32px;
+
+ line-height: 40px;
+ height: 40px;
+ min-width: 10em;
+
+ bottom: 0px;
+ left: 250px;
+
+ border: 1px solid #aaa;
+ background-color: white;
+}
+
+*[contenteditable] {
+ user-select: auto !important;
+ -webkit-user-select: auto !important;
+ -moz-user-select: auto !important;
+}
+
+#testtext {
+ user-select: auto !important;
+ -webkit-user-select: auto !important;
+ -moz-user-select: auto;
+}
+
+[contenteditable="true"]:focus {
+ outline: 1px solid #b1d6fd;
+ border: 1px solid #b1d6fd;
+}
+
diff --git a/static/js/paintbbs/PaintBBS-1.3.4.js b/static/js/paintbbs/PaintBBS-1.3.4.js
new file mode 100644
index 0000000..8450a49
--- /dev/null
+++ b/static/js/paintbbs/PaintBBS-1.3.4.js
@@ -0,0 +1,6171 @@
+'use strict';
+
+document.addEventListener("DOMContentLoaded", function() {
+ Neo.init();
+
+ if (!navigator.userAgent.match("Electron")) {
+ Neo.start();
+ }
+});
+
+
+var Neo = function() {};
+
+Neo.version = "1.3.4";
+Neo.painter;
+Neo.fullScreen = false;
+Neo.uploaded = false;
+
+Neo.config = {
+ width: 300,
+ height: 300,
+
+ colors: [
+ "#000000", "#FFFFFF",
+ "#B47575", "#888888",
+ "#FA9696", "#C096C0",
+ "#FFB6FF", "#8080FF",
+ "#25C7C9", "#E7E58D",
+ "#E7962D", "#99CB7B",
+ "#FCECE2", "#F9DDCF"
+ ]
+};
+
+Neo.reservePen = {};
+Neo.reserveEraser = {};
+
+Neo.SLIDERTYPE_RED = 0;
+Neo.SLIDERTYPE_GREEN = 1;
+Neo.SLIDERTYPE_BLUE = 2;
+Neo.SLIDERTYPE_ALPHA = 3;
+Neo.SLIDERTYPE_SIZE = 4;
+
+document.neo = Neo;
+
+Neo.init = function() {
+ var applets = document.getElementsByTagName('applet');
+ if (applets.length == 0) {
+ applets = document.getElementsByTagName('applet-dummy');
+ }
+
+ for (var i = 0; i < applets.length; i++) {
+ var applet = applets[i];
+ var name = applet.attributes.name.value;
+ if (name == "paintbbs") {
+ Neo.applet = applet;
+ Neo.initConfig(applet);
+ Neo.createContainer(applet);
+ Neo.init2();
+ }
+ }
+};
+
+Neo.init2 = function() {
+ var pageview = document.getElementById("pageView");
+ pageview.style.width = Neo.config.applet_width + "px";
+ pageview.style.height = Neo.config.applet_height + "px";
+
+ Neo.canvas = document.getElementById("canvas");
+ Neo.container = document.getElementById("container");
+ Neo.toolsWrapper = document.getElementById("toolsWrapper");
+
+ Neo.painter = new Neo.Painter();
+ Neo.painter.build(Neo.canvas, Neo.config.width, Neo.config.height);
+
+ Neo.container.oncontextmenu = function() {return false;};
+
+ // 続きから描く
+ if (Neo.config.image_canvas) {
+ Neo.painter.loadImage(Neo.config.image_canvas);
+ }
+
+ // 描きかけの画像が見つかったとき
+ Neo.storage = (Neo.isMobile()) ? localStorage : sessionStorage;
+ if (Neo.storage.getItem('timestamp')) {
+ setTimeout(function () {
+ if (confirm(Neo.translate("以前の編集データを復元しますか?"))) {
+ Neo.painter.loadSession();
+ }
+ }, 1);
+ }
+
+ window.addEventListener("pagehide", function(e) {
+ if (!Neo.uploaded) {
+ Neo.painter.saveSession();
+ } else {
+ Neo.painter.clearSession();
+ }
+ }, false);
+}
+
+Neo.initConfig = function(applet) {
+ if (applet) {
+ var name = applet.attributes.name.value || "neo";
+ var appletWidth = applet.attributes.width;
+ var appletHeight = applet.attributes.height;
+ if (appletWidth) Neo.config.applet_width = parseInt(appletWidth.value);
+ if (appletHeight) Neo.config.applet_height = parseInt(appletHeight.value);
+
+ var params = applet.getElementsByTagName('param');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i];
+ Neo.config[p.name] = Neo.fixConfig(p.value);
+
+ if (p.name == "image_width") Neo.config.width = parseInt(p.value);
+ if (p.name == "image_height") Neo.config.height = parseInt(p.value);
+ }
+
+ var emulationMode = Neo.config.neo_emulation_mode || "2.22_8x";
+ Neo.config.neo_alt_translation = emulationMode.slice(-1).match(/x/i);
+
+ Neo.readStyles();
+ Neo.applyStyle("color_bk", "#ccccff");
+ Neo.applyStyle("color_bk2", "#bbbbff");
+ Neo.applyStyle("color_tool_icon", "#e8dfae");
+ Neo.applyStyle("color_icon", "#ccccff");
+ Neo.applyStyle("color_iconselect", "#ffaaaa");
+ Neo.applyStyle("color_text", "#666699");
+ Neo.applyStyle("color_bar", "#6f6fae");
+ Neo.applyStyle("tool_color_button", "#e8dfae");
+ Neo.applyStyle("tool_color_button2", "#f8daaa");
+ Neo.applyStyle("tool_color_text", "#773333");
+ Neo.applyStyle("tool_color_bar", "#ddddff");
+ Neo.applyStyle("tool_color_frame", "#000000");
+
+ var e = document.getElementById("container");
+ Neo.config.inherit_color = Neo.getInheritColor(e);
+ if (!Neo.config.color_frame) Neo.config.color_frame = Neo.config.color_text;
+ }
+
+ Neo.config.reserves = [
+ { size:1,
+ color:"#000000", alpha:1.0,
+ tool:Neo.Painter.TOOLTYPE_PEN,
+ drawType:Neo.Painter.DRAWTYPE_FREEHAND
+ },
+ { size:5,
+ color:"#FFFFFF", alpha:1.0,
+ tool:Neo.Painter.TOOLTYPE_ERASER,
+ drawType:Neo.Painter.DRAWTYPE_FREEHAND
+ },
+ { size:10,
+ color:"#FFFFFF", alpha:1.0,
+ tool:Neo.Painter.TOOLTYPE_ERASER,
+ drawType:Neo.Painter.DRAWTYPE_FREEHAND
+ },
+ ];
+
+ Neo.reservePen = Neo.clone(Neo.config.reserves[0]);
+ Neo.reserveEraser = Neo.clone(Neo.config.reserves[1]);
+};
+
+Neo.fixConfig = function(value) {
+ // javaでは"#12345"を色として解釈するがjavascriptでは"#012345"に変換しないとだめ
+ if (value.match(/^#[0-9a-fA-F]{5}$/)) {
+ value = "#0" + value.slice(1);
+ }
+ return value;
+};
+
+Neo.initSkin = function() {
+ var sheet = document.styleSheets[0];
+ if (!sheet) {
+ var style = document.createElement("style");
+ document.head.appendChild(style); // must append before you can access sheet property
+ sheet = style.sheet;
+ }
+
+ Neo.styleSheet = sheet;
+
+ var lightBorder = Neo.multColor(Neo.config.color_icon, 1.3);
+ var darkBorder = Neo.multColor(Neo.config.color_icon, 0.7);
+ var lightBar = Neo.multColor(Neo.config.color_bar, 1.3);
+ var darkBar = Neo.multColor(Neo.config.color_bar, 0.7);
+ var bgImage = Neo.backgroundImage();
+
+ Neo.addRule(".NEO #container", "background-image", "url(" + bgImage + ")");
+ Neo.addRule(".NEO .colorSlider .label", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .sizeSlider .label", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .layerControl .label1", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .layerControl .label0", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .toolTipOn .label", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .toolTipOff .label", "color", Neo.config.tool_color_text);
+
+ Neo.addRule(".NEO #toolSet", "background-color", Neo.config.color_bk);
+ Neo.addRule(".NEO #tools", "color", Neo.config.tool_color_text);
+ Neo.addRule(".NEO .layerControl .bg", "border-bottom", "1px solid " + Neo.config.tool_color_text);
+
+ Neo.addRule(".NEO .buttonOn", "color", Neo.config.color_text);
+ Neo.addRule(".NEO .buttonOff", "color", Neo.config.color_text);
+
+ Neo.addRule(".NEO .buttonOff", "background-color", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff", "border-top", "1px solid ", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff", "border-left", "1px solid ", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff", "box-shadow", "0 0 0 1px " + Neo.config.color_icon + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO .buttonOff:hover", "background-color", Neo.config.color_icon);
+ Neo.addRule(".NEO .buttonOff:hover", "border-top", "1px solid " + lightBorder);
+ Neo.addRule(".NEO .buttonOff:hover", "border-left", "1px solid " + lightBorder);
+ Neo.addRule(".NEO .buttonOff:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "background-color", darkBorder);
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-top", "1px solid " + darkBorder);
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "border-left", "1px solid " + darkBorder);
+ Neo.addRule(".NEO .buttonOff:active, .NEO .buttonOn", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect + ", 0 0 0 2px " + Neo.config.color_frame);
+
+
+ Neo.addRule(".NEO #canvas", "border", "1px solid " + Neo.config.color_frame);
+ Neo.addRule(".NEO #scrollH, .NEO #scrollV", "background-color", Neo.config.color_icon);
+ Neo.addRule(".NEO #scrollH, .NEO #scrollV", "box-shadow", "0 0 0 1px white" + ", 0 0 0 2px " + Neo.config.color_frame);
+
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "background-color", Neo.config.color_bar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "box-shadow", "0 0 0 1px " + Neo.config.color_icon);
+ Neo.addRule(".NEO #scrollH div:hover, .NEO #scrollV div:hover", "box-shadow", "0 0 0 1px " + Neo.config.color_iconselect);
+
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-top", "1px solid " + lightBar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-left", "1px solid " + lightBar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-right", "1px solid " + darkBar);
+ Neo.addRule(".NEO #scrollH div, .NEO #scrollV div", "border-bottom", "1px solid " + darkBar);
+
+ Neo.addRule(".NEO .toolTipOn", "background-color", Neo.multColor(Neo.config.tool_color_button, 0.7));
+ Neo.addRule(".NEO .toolTipOff", "background-color", Neo.config.tool_color_button);
+ Neo.addRule(".NEO .toolTipFixed", "background-color", Neo.config.tool_color_button2);
+
+ Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "background-color", Neo.config.tool_color_bar);
+ Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar);
+ Neo.addRule(".NEO .reserveControl", "background-color", Neo.config.tool_color_bar);
+ Neo.addRule(".NEO .layerControl", "background-color", Neo.config.tool_color_bar);
+
+ Neo.addRule(".NEO .colorTipOn, .NEO .colorTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .toolTipOn, .NEO .toolTipOff", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .toolTipFixed", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .colorSlider, .NEO .sizeSlider", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .reserveControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .layerControl", "box-shadow", "0 0 0 1px " + Neo.config.tool_color_frame);
+ Neo.addRule(".NEO .reserveControl .reserve", "border", "1px solid " + Neo.config.tool_color_frame);
+
+ if (navigator.language.indexOf("ja") != 0) {
+ var labels = ["Fixed", "On", "Off"];
+ for (var i = 0; i < labels.length; i++) {
+ var selector = ".NEO .toolTip" + labels[i] + " .label";
+ Neo.addRule(selector, "letter-spacing", "0px !important");
+ }
+ }
+};
+
+Neo.addRule = function(selector, styleName, value, sheet) {
+ if (!sheet) sheet = Neo.styleSheet;
+ if (sheet.addRule) {
+ sheet.addRule(selector, styleName + ":" + value, sheet.rules.length);
+
+ } else if (sheet.insertRule) {
+ var rule = selector + "{" + styleName + ":" + value + "}";
+ var index = sheet.cssRules.length;
+ sheet.insertRule(rule, index);
+ }
+};
+
+Neo.readStyles = function() {
+ Neo.rules = {};
+ for (var i = 0; i < document.styleSheets.length; i++) {
+ Neo.readStyle(document.styleSheets[i]);
+ }
+};
+
+Neo.readStyle = function(sheet) {
+ try {
+ var rules = sheet.cssRules;
+ for (var i = 0; i < rules.length; i++) {
+ var rule = rules[i];
+ if (rule.styleSheet) {
+ Neo.readStyle(rule.styleSheet);
+ continue;
+ }
+
+ var selector = rule.selectorText
+ if (selector) {
+ selector = selector.replace(/^(.NEO\s+)?\./, '')
+
+ var css = rule.cssText || rule.style.cssText;
+ var result = css.match(/color:\s*(.*)\s*;/)
+ if (result) {
+ var hex = Neo.colorNameToHex(result[1]);
+ if (hex) {
+ Neo.rules[selector] = hex;
+ }
+ }
+ }
+ }
+ } catch (e) {}
+};
+
+Neo.applyStyle = function(name, defaultColor) {
+ if (Neo.config[name] == undefined) {
+ Neo.config[name] = Neo.rules[name] || defaultColor;
+ }
+};
+
+Neo.getInheritColor = function(e) {
+ var result = "#000000";
+ while (e && e.style) {
+ if (e.style.color != "") {
+ result = e.style.color;
+ break;
+ }
+ if (e.attributes["text"]) {
+ result = e.attributes["text"].value;
+ break;
+ }
+ e = e.parentNode;
+ }
+ return result;
+};
+
+Neo.backgroundImage = function() {
+ var c1 = Neo.painter.getColor(Neo.config.color_bk) | 0xff000000;
+ var c2 = Neo.painter.getColor(Neo.config.color_bk2) | 0xff000000;
+ var bgCanvas = document.createElement("canvas");
+ bgCanvas.width = 16;
+ bgCanvas.height = 16;
+ var ctx = bgCanvas.getContext("2d");
+ var imageData = ctx.getImageData(0, 0, 16, 16);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var index = 0;
+ for (var y = 0; y < 16; y++) {
+ for (var x = 0; x < 16; x++) {
+ buf32[index++] = (x == 14 || y == 14) ? c2 : c1;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+ return bgCanvas.toDataURL('image/png');
+};
+
+Neo.multColor = function(c, scale) {
+ var r = Math.round(parseInt(c.substr(1, 2), 16) * scale);
+ var g = Math.round(parseInt(c.substr(3, 2), 16) * scale);
+ var b = Math.round(parseInt(c.substr(5, 2), 16) * scale);
+ r = ("0" + Math.min(Math.max(r, 0), 255).toString(16)).substr(-2);
+ g = ("0" + Math.min(Math.max(g, 0), 255).toString(16)).substr(-2);
+ b = ("0" + Math.min(Math.max(b, 0), 255).toString(16)).substr(-2);
+ return '#' + r + g + b;
+};
+
+Neo.colorNameToHex = function(name) {
+ var colors = {"aliceblue":"#f0f8ff", "antiquewhite":"#faebd7", "aqua":"#00ffff","aquamarine":"#7fffd4", "azure":"#f0ffff", "beige":"#f5f5dc", "bisque":"#ffe4c4", "black":"#000000", "blanchedalmond":"#ffebcd", "blue":"#0000ff", "blueviolet":"#8a2be2", "brown":"#a52a2a", "burlywood":"#deb887", "cadetblue":"#5f9ea0", "chartreuse":"#7fff00", "chocolate":"#d2691e", "coral":"#ff7f50", "cornflowerblue":"#6495ed", "cornsilk":"#fff8dc", "crimson":"#dc143c", "cyan":"#00ffff", "darkblue":"#00008b", "darkcyan":"#008b8b", "darkgoldenrod":"#b8860b", "darkgray":"#a9a9a9", "darkgreen":"#006400", "darkkhaki":"#bdb76b", "darkmagenta":"#8b008b", "darkolivegreen":"#556b2f", "darkorange":"#ff8c00", "darkorchid":"#9932cc", "darkred":"#8b0000", "darksalmon":"#e9967a", "darkseagreen":"#8fbc8f", "darkslateblue":"#483d8b", "darkslategray":"#2f4f4f", "darkturquoise":"#00ced1", "darkviolet":"#9400d3", "deeppink":"#ff1493", "deepskyblue":"#00bfff", "dimgray":"#696969", "dodgerblue":"#1e90ff", "firebrick":"#b22222", "floralwhite":"#fffaf0", "forestgreen":"#228b22", "fuchsia":"#ff00ff", "gainsboro":"#dcdcdc", "ghostwhite":"#f8f8ff", "gold":"#ffd700", "goldenrod":"#daa520", "gray":"#808080", "green":"#008000", "greenyellow":"#adff2f", "honeydew":"#f0fff0", "hotpink":"#ff69b4", "indianred ":"#cd5c5c", "indigo":"#4b0082", "ivory":"#fffff0", "khaki":"#f0e68c", "lavender":"#e6e6fa", "lavenderblush":"#fff0f5", "lawngreen":"#7cfc00", "lemonchiffon":"#fffacd", "lightblue":"#add8e6", "lightcoral":"#f08080", "lightcyan":"#e0ffff", "lightgoldenrodyellow":"#fafad2", "lightgrey":"#d3d3d3", "lightgreen":"#90ee90", "lightpink":"#ffb6c1", "lightsalmon":"#ffa07a", "lightseagreen":"#20b2aa", "lightskyblue":"#87cefa", "lightslategray":"#778899", "lightsteelblue":"#b0c4de", "lightyellow":"#ffffe0", "lime":"#00ff00", "limegreen":"#32cd32", "linen":"#faf0e6", "magenta":"#ff00ff", "maroon":"#800000", "mediumaquamarine":"#66cdaa", "mediumblue":"#0000cd", "mediumorchid":"#ba55d3", "mediumpurple":"#9370d8", "mediumseagreen":"#3cb371", "mediumslateblue":"#7b68ee", "mediumspringgreen":"#00fa9a", "mediumturquoise":"#48d1cc", "mediumvioletred":"#c71585", "midnightblue":"#191970", "mintcream":"#f5fffa", "mistyrose":"#ffe4e1", "moccasin":"#ffe4b5", "navajowhite":"#ffdead", "navy":"#000080", "oldlace":"#fdf5e6", "olive":"#808000", "olivedrab":"#6b8e23", "orange":"#ffa500", "orangered":"#ff4500", "orchid":"#da70d6", "palegoldenrod":"#eee8aa", "palegreen":"#98fb98", "paleturquoise":"#afeeee", "palevioletred":"#d87093", "papayawhip":"#ffefd5", "peachpuff":"#ffdab9", "peru":"#cd853f", "pink":"#ffc0cb", "plum":"#dda0dd", "powderblue":"#b0e0e6", "purple":"#800080", "rebeccapurple":"#663399", "red":"#ff0000", "rosybrown":"#bc8f8f", "royalblue":"#4169e1", "saddlebrown":"#8b4513", "salmon":"#fa8072", "sandybrown":"#f4a460", "seagreen":"#2e8b57", "seashell":"#fff5ee", "sienna":"#a0522d", "silver":"#c0c0c0", "skyblue":"#87ceeb", "slateblue":"#6a5acd", "slategray":"#708090", "snow":"#fffafa", "springgreen":"#00ff7f", "steelblue":"#4682b4", "tan":"#d2b48c", "teal":"#008080", "thistle":"#d8bfd8", "tomato":"#ff6347", "turquoise":"#40e0d0", "violet":"#ee82ee", "wheat":"#f5deb3", "white":"#ffffff", "whitesmoke":"#f5f5f5", "yellow":"#ffff00", "yellowgreen":"#9acd32"};
+
+ var rgb = name.toLowerCase().match(/rgb\((.*),(.*),(.*)\)/);
+ if (rgb) {
+ var r = ("0" + parseInt(rgb[1]).toString(16)).slice(-2)
+ var g = ("0" + parseInt(rgb[2]).toString(16)).slice(-2)
+ var b = ("0" + parseInt(rgb[3]).toString(16)).slice(-2)
+ return "#" + r + g + b
+ }
+
+ if (typeof colors[name.toLowerCase()] != 'undefined') {
+ return colors[name.toLowerCase()];
+ }
+ return false;
+};
+
+Neo.initComponents = function() {
+ document.getElementById("copyright").innerHTML += "v" + Neo.version;
+
+ // アプレットのborderの動作をエミュレート
+ if (navigator.userAgent.search("FireFox") > -1) {
+ var container = document.getElementById("container");
+ container.addEventListener("mousedown", function(e) {
+ container.style.borderColor = Neo.config.inherit_color;
+ e.stopPropagation();
+ }, false);
+ document.addEventListener("mousedown", function(e) {
+ container.style.borderColor = 'transparent';
+ }, false);
+ }
+
+ // ドラッグしたまま画面外に移動した時
+ document.addEventListener("mouseup", function(e) {
+ if (Neo.painter && !Neo.painter.isContainer(e.target)) {
+ Neo.painter.cancelTool(e.target);
+ }
+ }, false);
+
+ // 投稿に失敗する可能性があるときは警告を表示する
+ Neo.showWarning();
+
+ if (Neo.styleSheet) {
+ Neo.addRule("*", "user-select", "none");
+ Neo.addRule("*", "-webkit-user-select", "none");
+ Neo.addRule("*", "-ms-user-select", "none");
+ }
+}
+
+Neo.initButtons = function() {
+ new Neo.Button().init("undo").onmouseup = function() {
+ new Neo.UndoCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("redo").onmouseup = function () {
+ new Neo.RedoCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("window").onmouseup = function() {
+ new Neo.WindowCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("submit").onmouseup = function() {
+ new Neo.SubmitCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("copyright").onmouseup = function() {
+ new Neo.CopyrightCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("zoomPlus").onmouseup = function() {
+ new Neo.ZoomPlusCommand(Neo.painter).execute();
+ };
+ new Neo.Button().init("zoomMinus").onmouseup = function() {
+ new Neo.ZoomMinusCommand(Neo.painter).execute();
+ };
+
+ Neo.fillButton = new Neo.FillButton().init("fill");
+ Neo.rightButton = new Neo.RightButton().init("right");
+
+ if (Neo.isMobile()) {
+ Neo.rightButton.element.style.display = "block";
+ }
+
+ // toolTip
+ Neo.penTip = new Neo.PenTip().init("pen");
+ Neo.pen2Tip = new Neo.Pen2Tip().init("pen2");
+ Neo.effectTip = new Neo.EffectTip().init("effect");
+ Neo.effect2Tip = new Neo.Effect2Tip().init("effect2");
+ Neo.eraserTip = new Neo.EraserTip().init("eraser");
+ Neo.drawTip = new Neo.DrawTip().init("draw");
+ Neo.maskTip = new Neo.MaskTip().init("mask");
+
+ Neo.toolButtons = [Neo.fillButton,
+ Neo.penTip,
+ Neo.pen2Tip,
+ Neo.effectTip,
+ Neo.effect2Tip,
+ Neo.drawTip,
+ Neo.eraserTip];
+
+ // colorTip
+ for (var i = 1; i <= 14; i++) {
+ new Neo.ColorTip().init("color" + i, {index:i});
+ };
+
+ // colorSlider
+ Neo.sliders[Neo.SLIDERTYPE_RED] = new Neo.ColorSlider().init(
+ "sliderRed", {type:Neo.SLIDERTYPE_RED});
+ Neo.sliders[Neo.SLIDERTYPE_GREEN] = new Neo.ColorSlider().init(
+ "sliderGreen", {type:Neo.SLIDERTYPE_GREEN});
+ Neo.sliders[Neo.SLIDERTYPE_BLUE] = new Neo.ColorSlider().init(
+ "sliderBlue", {type:Neo.SLIDERTYPE_BLUE});
+ Neo.sliders[Neo.SLIDERTYPE_ALPHA] = new Neo.ColorSlider().init(
+ "sliderAlpha", {type:Neo.SLIDERTYPE_ALPHA});
+
+ // sizeSlider
+ Neo.sliders[Neo.SLIDERTYPE_SIZE] = new Neo.SizeSlider().init(
+ "sliderSize", {type:Neo.SLIDERTYPE_SIZE});
+
+ // reserveControl
+ for (var i = 1; i <= 3; i++) {
+ new Neo.ReserveControl().init("reserve" + i, {index:i});
+ };
+
+ new Neo.LayerControl().init("layerControl");
+ new Neo.ScrollBarButton().init("scrollH");
+ new Neo.ScrollBarButton().init("scrollV");
+};
+
+Neo.start = function(isApp) {
+ if (!Neo.painter) return;
+
+ Neo.initSkin();
+ Neo.initComponents();
+ Neo.initButtons();
+
+ Neo.isApp = isApp;
+ if (Neo.applet) {
+ var name = Neo.applet.attributes.name.value || "paintbbs";
+ Neo.applet.outerHTML = "";
+ document[name] = Neo;
+
+ Neo.resizeCanvas();
+ Neo.container.style.visibility = "visible";
+
+ if (Neo.isApp) {
+ var ipc = require('electron').ipcRenderer;
+ ipc.sendToHost('neo-status', 'ok');
+
+ } else {
+ if (document.paintBBSCallback) {
+ document.paintBBSCallback('start');
+ }
+ }
+ }
+};
+
+Neo.isIE = function() {
+ var ms = false;
+ if (/MSIE 10/i.test(navigator.userAgent)) {
+ ms = true; // This is internet explorer 10
+ }
+ if (/MSIE 9/i.test(navigator.userAgent) ||
+ /rv:11.0/i.test(navigator.userAgent)) {
+ ms = true; // This is internet explorer 9 or 11
+ }
+ return ms
+};
+
+Neo.isMobile = function() {
+ return navigator.userAgent.match(/Android|iPhone|iPad|iPod/i);
+};
+
+Neo.showWarning = function() {
+ var futaba = location.hostname.match(/2chan.net/i);
+ var samplebbs = location.hostname.match(/neo.websozai.jp/i);
+
+ var chrome = navigator.userAgent.match(/Chrome\/(\d+)/i);
+ if (chrome && chrome.length > 1) chrome = chrome[1];
+
+ var edge = navigator.userAgent.match(/Edge\/(\d+)/i);
+ if (edge && edge.length > 1) edge = edge[1];
+
+ var ms = Neo.isIE();
+
+ var str = "";
+ if (futaba || samplebbs) {
+ if (ms || (edge && edge < 15)) {
+ str = Neo.translate("このブラウザでは<br>投稿に失敗することがあります<br>");
+ }
+ }
+
+ // もし<PARAM NAME="neo_warning" VALUE="...">があれば表示する
+ if (Neo.config.neo_warning) {
+ str += Neo.config.neo_warning;
+ }
+
+ var warning = document.getElementById("neoWarning")
+ warning.innerHTML = str;
+ setTimeout(function() { warning.style.opacity = "0"; }, 15000);
+};
+
+/*
+ -----------------------------------------------------------------------
+ UIの更新
+ -----------------------------------------------------------------------
+*/
+
+Neo.updateUI = function() {
+ var current = Neo.painter.tool.getToolButton();
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ if (current) {
+ if (current == toolTip) {
+ toolTip.setSelected(true);
+ toolTip.update();
+ } else {
+ toolTip.setSelected(false);
+ }
+ }
+ }
+ if (Neo.drawTip) {
+ Neo.drawTip.update();
+ }
+
+ Neo.updateUIColor(true, false);
+}
+
+Neo.updateUIColor = function(updateSlider, updateColorTip) {
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ toolTip.update();
+ }
+
+ if (updateSlider) {
+ for (var i = 0; i < Neo.sliders.length; i++) {
+ var slider = Neo.sliders[i];
+ slider.update();
+ }
+ }
+
+ // パレットを変更するとき
+ if (updateColorTip) {
+ var colorTip = Neo.ColorTip.getCurrent();
+ if (colorTip) {
+ colorTip.setColor(Neo.painter.foregroundColor);
+ }
+ }
+};
+
+/*
+ -----------------------------------------------------------------------
+ リサイズ対応
+ -----------------------------------------------------------------------
+*/
+
+Neo.updateWindow = function() {
+ if (Neo.fullScreen) {
+ document.getElementById("windowView").style.display = "block";
+ document.getElementById("windowView").appendChild(Neo.container);
+
+ } else {
+ document.getElementById("windowView").style.display = "none";
+ document.getElementById("pageView").appendChild(Neo.container);
+ }
+ Neo.resizeCanvas();
+};
+
+Neo.resizeCanvas = function() {
+ var appletWidth = Neo.container.clientWidth;
+ var appletHeight = Neo.container.clientHeight;
+
+ var canvasWidth = Neo.painter.canvasWidth;
+ var canvasHeight = Neo.painter.canvasHeight;
+
+ var width0 = canvasWidth * Neo.painter.zoom;
+ var height0 = canvasHeight * Neo.painter.zoom;
+
+ var width = (width0 < appletWidth - 100) ? width0 : appletWidth - 100;
+ var height = (height0 < appletHeight - 120) ? height0 : appletHeight - 120;
+
+ //width, heightは偶数でないと誤差が出るため
+ width = Math.floor(width / 2) * 2;
+ height = Math.floor(height / 2) * 2;
+
+ Neo.painter.destWidth = width;
+ Neo.painter.destHeight = height;
+
+ Neo.painter.destCanvas.width = width;
+ Neo.painter.destCanvas.height = height;
+ Neo.painter.destCanvasCtx = Neo.painter.destCanvas.getContext("2d");
+ Neo.painter.destCanvasCtx.imageSmoothingEnabled = false;
+ Neo.painter.destCanvasCtx.mozImageSmoothingEnabled = false;
+
+ Neo.canvas.style.width = width + "px";
+ Neo.canvas.style.height = height + "px";
+
+ var top = (Neo.container.clientHeight - toolsWrapper.clientHeight) / 2;
+ Neo.toolsWrapper.style.top = ((top > 0) ? top : 0) + "px";
+
+ if (top < 0) {
+ var s = Neo.container.clientHeight / toolsWrapper.clientHeight;
+ Neo.toolsWrapper.style.transform =
+ "translate(0, " + top + "px) scale(1," + s + ")";
+ } else {
+ Neo.toolsWrapper.style.transform = "";
+ }
+
+ Neo.painter.setZoom(Neo.painter.zoom);
+ Neo.painter.updateDestCanvas(0, 0, canvasWidth, canvasHeight);
+};
+
+/*
+ -----------------------------------------------------------------------
+ 投稿
+ -----------------------------------------------------------------------
+*/
+
+Neo.clone = function(src) {
+ var dst = {};
+ for (var k in src) {
+ dst[k] = src[k];
+ }
+ return dst;
+};
+
+Neo.getSizeString = function(len) {
+ var result = String(len);
+ while (result.length < 8) {
+ result = "0" + result;
+ }
+ return result;
+};
+
+Neo.openURL = function(url) {
+ if (Neo.isApp) {
+ require('electron').shell.openExternal(url);
+
+ } else {
+ window.open(url, '_blank');
+ }
+};
+
+Neo.submit = function(board, blob, thumbnail, thumbnail2) {
+ var url = Neo.config.url_save;
+ var headerString = Neo.str_header || "";
+ console.log("submit url=" + url + " header=" + headerString);
+
+ if (document.paintBBSCallback) {
+ var result = document.paintBBSCallback('check')
+ if (result == 0 || result == "false") {
+ return;
+ }
+
+ result = document.paintBBSCallback('header')
+ if (result && typeof result == "string") {
+ headerString == result;
+ }
+ }
+ if (!headerString) headerString = Neo.config.send_header || "";
+
+ var imageType = Neo.config.send_header_image_type;
+ if (imageType && imageType == "true") {
+ headerString = "image_type=png&" + headerString
+ console.log("header=" + headerString);
+ }
+
+ var header = new Blob([headerString]);
+ var headerLength = this.getSizeString(header.size);
+ var imgLength = this.getSizeString(blob.size);
+
+ var array = ['P', // PaintBBS
+ headerLength,
+ header,
+ imgLength,
+ '\r\n',
+ blob];
+
+ if (thumbnail) {
+ var thumbnailLength = this.getSizeString(thumbnail.size);
+ array.push(thumbnailLength, thumbnail);
+ }
+ if (thumbnail2) {
+ var thumbnail2Length = this.getSizeString(thumbnail2.size);
+ array.push(thumbnail2Length, thumbnail2);
+ }
+
+ var body = new Blob(array, {type: 'application/octet-binary'}); //これが必要!!
+
+ var request = new XMLHttpRequest();
+ request.open("POST", url, true);
+
+ request.onload = function(e) {
+ console.log(request.response);
+ Neo.uploaded = true;
+
+ /*var url = Neo.config.url_exit;
+ if (url[0] == '/') {
+ url = url.replace(/^.*\//, ''); //よくわかんないけどとりあえず
+ }
+
+ // ふたばのpaintpost.phpは、画像投稿に成功するとresponseに
+ // "./futaba.php?mode=paintcom&amp;painttmp=.png"
+ // という文字列を返します。
+ //
+ // NEOでは、responseに文字列"painttmp="が含まれる場合は
+ // <PARAM>で指定されたurl_exitを無視して、このURLにジャンプします。
+ var responseURL = request.response.replace(/&amp;/g, '&');
+ if (responseURL.match(/painttmp=/)) {
+ url = responseURL;
+ }
+ var exitURL = url;
+
+ // しぃちゃんのドキュメントをよく見たら
+ // responseが "URL:〜" の形だった場合はそこへ飛ばすって書いてありました。
+ // こっちを使うべきでした……
+ if (responseURL.match(/^URL:/)) {
+ exitURL = responseURL.replace(/^URL:/, '');
+ }
+
+ location.href = exitURL;*/
+ location.href = Neo.config.url_exit;
+ };
+ request.onerror = function(e) {
+ console.log("error");
+ };
+ request.onabort = function(e) {
+ console.log("abort");
+ };
+ request.ontimeout = function(e) {
+ console.log("timeout");
+ };
+
+ request.send(body);
+};
+
+/*
+ -----------------------------------------------------------------------
+ LiveConnect
+ -----------------------------------------------------------------------
+*/
+
+Neo.getColors = function() {
+ console.log("getColors")
+ console.log("defaultColors==", Neo.config.colors.join('\n'));
+ var array = []
+ for (var i = 0; i < 14; i++) {
+ array.push(Neo.colorTips[i].color)
+ }
+ return array.join('\n');
+ // return Neo.config.colors.join('\n');
+};
+
+Neo.setColors = function(colors) {
+ console.log("setColors");
+ var array = colors.split('\n');
+ for (var i = 0; i < 14; i++) {
+ var color = array[i];
+ Neo.config.colors[i] = color;
+ Neo.colorTips[i].setColor(color);
+ }
+};
+
+
+Neo.pExit = function() {
+ new Neo.SubmitCommand(Neo.painter).execute();
+};
+
+Neo.str_header = "";
+
+/*
+ -----------------------------------------------------------------------
+ DOMツリーの作成
+ -----------------------------------------------------------------------
+*/
+
+Neo.createContainer = function(applet) {
+ var neo = document.createElement("div");
+ neo.className = "NEO";
+ neo.id = "NEO";
+ var html = (function() {/*
+
+<script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
+
+<div id="pageView" style="width:450px; height:470px; margin:auto;">
+<div id="container" style="visibility:hidden;" class="o">
+<div id="center" class="o">
+<div id="painterContainer" class="o">
+<div id="painterWrapper" class="o">
+<div id="upper" class="o">
+<div id="redo">[やり直し]</div>
+<div id="undo">[元に戻す]</div>
+<div id="fill">[塗り潰し]</div>
+<div id="right" style="display:none;">[右]</div>
+</div>
+<div id="painter">
+<div id="canvas"> <!-- class="o">-->
+<div id="scrollH"></div>
+<div id="scrollV"></div>
+<div id="zoomPlusWrapper">
+<div id="zoomPlus">+</div>
+</div>
+<div id="zoomMinusWrapper">
+<div id="zoomMinus">-</div>
+</div>
+<div id="neoWarning"></div>
+</div>
+</div>
+<div id="lower" class="o">
+</div>
+</div>
+<div id="toolsWrapper">
+<div id="tools">
+<div id="toolSet">
+<div id="pen"></div>
+<div id="pen2"></div>
+<div id="effect"></div>
+<div id="effect2"></div>
+<div id="eraser"></div>
+<div id="draw"></div>
+<div id="mask"></div>
+
+<div class="colorTips">
+<div id="color2"></div><div id="color1"></div><br>
+<div id="color4"></div><div id="color3"></div><br>
+<div id="color6"></div><div id="color5"></div><br>
+<div id="color8"></div><div id="color7"></div><br>
+<div id="color10"></div><div id="color9"></div><br>
+<div id="color12"></div><div id="color11"></div><br>
+<div id="color14"></div><div id="color13"></div>
+</div>
+
+<div id="sliderRed"></div>
+<div id="sliderGreen"></div>
+<div id="sliderBlue"></div>
+<div id="sliderAlpha"></div>
+<div id="sliderSize"></div>
+
+<div class="reserveControl" style="margin-top:4px;">
+<div id="reserve1"></div>
+<div id="reserve2"></div>
+<div id="reserve3"></div>
+</div>
+<div id="layerControl" style="margin-top:6px;"></div>
+
+<!--<div id="toolPad" style="height:20px;"></div>-->
+</div>
+</div>
+</div>
+</div>
+</div>
+<div id="headerButtons">
+<div id="window">[窓]</div>
+</div>
+<div id="footerButtons">
+<div id="submit">[投稿]</div>
+<div id="copyright">[(C)しぃちゃん PaintBBS NEO]</div>
+</div>
+</div>
+</div>
+
+<div id="windowView" style="display: none;">
+
+</div>
+
+
+ */}).toString().match(/\/\*([^]*)\*\//)[1];
+
+ neo.innerHTML = html.replace(/\[(.*?)\]/g, function(match, str) {
+ return Neo.translate(str)
+ })
+
+ var parent = applet.parentNode;
+ parent.appendChild(neo);
+ parent.insertBefore(neo, applet);
+
+ // applet.style.display = "none";
+
+ // NEOを組み込んだURLをアプリ版で開くとDOMツリーが2重にできて格好悪いので消しておく
+ setTimeout(function() {
+ var tmp = document.getElementsByClassName("NEO");
+ if (tmp.length > 1) {
+ for (var i = 1; i < tmp.length; i++) {
+ tmp[i].style.display = "none";
+ }
+ }
+ }, 0);
+};
+
+
+'use strict';
+
+Neo.dictionary = {
+ "ja": {},
+ "en": {
+ "やり直し": "Redo",
+ "元に戻す": "Undo",
+ "塗り潰し": "Paint",
+ "窓": "F&nbsp;",
+ "投稿": "Send",
+ "(C)しぃちゃん PaintBBS NEO": "(C)shi-chan PaintBBS NEO",
+ "鉛筆": "Solid",
+ "水彩": "WaterC",
+ "テキスト": "Text",
+ "トーン": "Tone",
+ "ぼかし": "ShadeOff",
+ "覆い焼き": "HLight",
+ "焼き込み": "Dark",
+ "消しペン": "White",
+ "消し四角": "WhiteRect",
+ "全消し": "Clear",
+ "四角": "Rect",
+ "線四角": "LineRect",
+ "楕円": "Oval",
+ "線楕円": "LineOval",
+ "コピー": "Copy",
+ "レイヤ結合": "lay-unif",
+ "角取り": "Antialias",
+ "左右反転": "reverseL",
+ "上下反転": "reverseU",
+ "傾け": "lie",
+ "通常": "Normal",
+ "マスク": "Mask",
+ "逆マスク": "ReMask",
+ "加算": "And",
+ "逆加算": "Div",
+ "手書き": "FreeLine",
+ "直線": "Straight",
+ "BZ曲線": "Bezie",
+ "ページビュー?": "Page view?",
+ "ウィンドウビュー?": "Window view?",
+ "以前の編集データを復元しますか?": "Restore session?",
+ "右": "Right Click",
+
+ "PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?": "PaintBBS NEO is an HTML5 port of Oekaki Shi-BBS PaintBBS (©2000-2004 shi-chan). Show the project page?",
+ "このブラウザでは<br>投稿に失敗することがあります<br>": "This browser may fail to send your picture.<br>",
+ },
+ "enx": {
+ "やり直し": "Redo",
+ "元に戻す": "Undo",
+ "塗り潰し": "Fill",
+ "窓": "Float",
+ "投稿": "Send",
+ "(C)しぃちゃん PaintBBS NEO": "&copy;shi-cyan PaintBBS NEO",
+ "鉛筆": "Solid",
+ "水彩": "WaterCo",
+ "テキスト": "Text",
+ "トーン": "Halftone",
+ "ぼかし": "Blur",
+ "覆い焼き": "Light",
+ "焼き込み": "Dark",
+ "消しペン": "White",
+ "消し四角": "WhiteRe",
+ "全消し": "Clear",
+ "四角": "Rect",
+ "線四角": "LineRect",
+ "楕円": "Oval",
+ "線楕円": "LineOval",
+ "コピー": "Copy",
+ "レイヤ結合": "layerUnit",
+ "角取り": "antiAlias",
+ "左右反転": "flipHorita",
+ "上下反転": "flipVertic",
+ "傾け": "rotate",
+ "通常": "Normal",
+ "マスク": "Mask",
+ "逆マスク": "ReMask",
+ "加算": "And",
+ "逆加算": "Divide",
+ "手書き": "Freehan",
+ "直線": "Line",
+ "BZ曲線": "Bezier",
+ "Layer0": "LayerBG",
+ "Layer1": "LayerFG",
+ "ページビュー?": "Page view?",
+ "ウィンドウビュー?": "Window view?",
+ "以前の編集データを復元しますか?": "Restore session?",
+ "右": "Right Click",
+
+ "PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?": "PaintBBS NEO is an HTML5 port of Oekaki Shi-BBS PaintBBS (©2000-2004 shi-chan). Show the project page?",
+ "このブラウザでは<br>投稿に失敗することがあります<br>": "This browser may fail to send your picture.<br>",
+ },
+ "es": {
+ "やり直し": "Rehacer",
+ "元に戻す": "Deshacer",
+ "塗り潰し": "Llenar",
+ "窓": "Ventana",
+ "投稿": "Enviar",
+ "(C)しぃちゃん PaintBBS NEO": "&copy;shi-cyan PaintBBS NEO",
+ "鉛筆": "Lápiz",
+ "水彩": "Acuarela",
+ "テキスト": "Texto",
+ "トーン": "Tono",
+ "ぼかし": "Gradación",
+ "覆い焼き": "Sobreexp.",
+ "焼き込み": "Quemar",
+ "消しペン": "Goma",
+ "消し四角": "GomaRect",
+ "全消し": "Borrar",
+ "四角": "Rect",
+ "線四角": "LíneaRect",
+ "楕円": "Óvalo",
+ "線楕円": "LíneaÓvalo",
+ "コピー": "Copiar",
+ "レイヤ結合": "UnirCapa",
+ "角取り": "Antialias",
+ "左右反転": "Inv.Izq/Der",
+ "上下反転": "Inv.Arr/Aba",
+ "傾け": "Inclinar",
+ "通常": "Normal",
+ "マスク": "Masc.",
+ "逆マスク": "Masc.Inv",
+ "加算": "Adición",
+ "逆加算": "Subtrac",
+ "手書き": "Libre",
+ "直線": "Línea",
+ "BZ曲線": "Curva",
+ "Layer0": "Capa0",
+ "Layer1": "Capa1",
+ "ページビュー?": "¿Vista de página?",
+ "ウィンドウビュー?": "¿Vista de ventana?",
+ "以前の編集データを復元しますか?": "¿Restaurar sesión anterior?",
+ "右": "Clic derecho",
+
+ "PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?":
+ "PaintBBS NEO es una versión para HTML5 de Oekaki Shi-BBS PaintBBS (© 2000-2004 shi-chan). ¿Mostrar la página del proyecto?",
+ "このブラウザでは<br>投稿に失敗することがあります<br>": "Este navegador podría no enviar su imagen.<br>",
+ },
+};
+
+Neo.translate = function () {
+ var language = (window.navigator.languages && window.navigator.languages[0]) ||
+ window.navigator.language ||
+ window.navigator.userLanguage ||
+ window.navigator.browserLanguage;
+
+ var lang = "en";
+ for (var key in Neo.dictionary) {
+ if (language.indexOf(key) == 0) {
+ lang = key;
+ break;
+ }
+ }
+
+ return function(string) {
+ if (Neo.config.neo_alt_translation) {
+ if (lang == "en") lang = "enx"
+ } else {
+ if (lang != "ja") lang = "en"
+ }
+ return Neo.dictionary[lang][string] || string;
+ }
+}();
+
+
+'use strict';
+
+Neo.Painter = function() {
+ this._undoMgr = new Neo.UndoManager(50);
+};
+
+Neo.Painter.prototype.container;
+Neo.Painter.prototype._undoMgr;
+Neo.Painter.prototype.tool;
+Neo.Painter.prototype.inputText;
+
+//Canvas Info
+Neo.Painter.prototype.canvasWidth;
+Neo.Painter.prototype.canvasHeight;
+Neo.Painter.prototype.canvas = [];
+Neo.Painter.prototype.canvasCtx = [];
+Neo.Painter.prototype.visible = [];
+Neo.Painter.prototype.current = 0;
+
+//Temp Canvas Info
+Neo.Painter.prototype.tempCanvas;
+Neo.Painter.prototype.tempCanvasCtx;
+Neo.Painter.prototype.tempX = 0;
+Neo.Painter.prototype.tempY = 0;
+
+//Destination Canvas for display
+Neo.Painter.prototype.destCanvas;
+Neo.Painter.prototype.destCanvasCtx;
+
+
+Neo.Painter.prototype.backgroundColor = "#ffffff";
+Neo.Painter.prototype.foregroundColor = "#000000";
+
+Neo.Painter.prototype.lineWidth = 1;
+Neo.Painter.prototype.alpha = 1;
+Neo.Painter.prototype.zoom = 1;
+Neo.Painter.prototype.zoomX = 0;
+Neo.Painter.prototype.zoomY = 0;
+
+Neo.Painter.prototype.isMouseDown;
+Neo.Painter.prototype.isMouseDownRight;
+Neo.Painter.prototype.prevMouseX;
+Neo.Painter.prototype.prevMouseY;
+Neo.Painter.prototype.mouseX;
+Neo.Painter.prototype.mouseY;
+
+Neo.Painter.prototype.slowX = 0;
+Neo.Painter.prototype.slowY = 0;
+Neo.Painter.prototype.stab = null;
+
+Neo.Painter.prototype.isShiftDown = false;
+Neo.Painter.prototype.isCtrlDown = false;
+Neo.Painter.prototype.isAltDown = false;
+
+//Neo.Painter.prototype.touchModifier = null;
+Neo.Painter.prototype.virtualRight = false;
+Neo.Painter.prototype.virtualShift = false;
+
+//Neo.Painter.prototype.onUpdateCanvas;
+Neo.Painter.prototype._roundData = [];
+Neo.Painter.prototype._toneData = [];
+Neo.Painter.prototype.toolStack = [];
+
+Neo.Painter.prototype.maskType = 0;
+Neo.Painter.prototype.drawType = 0;
+Neo.Painter.prototype.maskColor = "#000000";
+Neo.Painter.prototype._currentColor = [];
+Neo.Painter.prototype._currentMask = [];
+
+Neo.Painter.prototype.aerr;
+
+Neo.Painter.LINETYPE_NONE = 0;
+Neo.Painter.LINETYPE_PEN = 1;
+Neo.Painter.LINETYPE_ERASER = 2;
+Neo.Painter.LINETYPE_BRUSH = 3;
+Neo.Painter.LINETYPE_TONE = 4;
+Neo.Painter.LINETYPE_DODGE = 5;
+Neo.Painter.LINETYPE_BURN = 6;
+
+Neo.Painter.MASKTYPE_NONE = 0;
+Neo.Painter.MASKTYPE_NORMAL = 1;
+Neo.Painter.MASKTYPE_REVERSE = 2;
+Neo.Painter.MASKTYPE_ADD = 3;
+Neo.Painter.MASKTYPE_SUB = 4;
+
+Neo.Painter.DRAWTYPE_FREEHAND = 0;
+Neo.Painter.DRAWTYPE_LINE = 1;
+Neo.Painter.DRAWTYPE_BEZIER = 2;
+
+Neo.Painter.ALPHATYPE_NONE = 0;
+Neo.Painter.ALPHATYPE_PEN = 1;
+Neo.Painter.ALPHATYPE_FILL = 2;
+Neo.Painter.ALPHATYPE_BRUSH = 3;
+
+Neo.Painter.TOOLTYPE_NONE = 0;
+Neo.Painter.TOOLTYPE_PEN = 1;
+Neo.Painter.TOOLTYPE_ERASER = 2;
+Neo.Painter.TOOLTYPE_HAND = 3;
+Neo.Painter.TOOLTYPE_SLIDER = 4;
+Neo.Painter.TOOLTYPE_FILL = 5;
+Neo.Painter.TOOLTYPE_MASK = 6;
+Neo.Painter.TOOLTYPE_ERASEALL = 7;
+Neo.Painter.TOOLTYPE_ERASERECT = 8;
+Neo.Painter.TOOLTYPE_COPY = 9;
+Neo.Painter.TOOLTYPE_PASTE = 10;
+Neo.Painter.TOOLTYPE_MERGE = 11;
+Neo.Painter.TOOLTYPE_FLIP_H = 12;
+Neo.Painter.TOOLTYPE_FLIP_V = 13;
+
+Neo.Painter.TOOLTYPE_BRUSH = 14;
+Neo.Painter.TOOLTYPE_TEXT = 15;
+Neo.Painter.TOOLTYPE_TONE = 16;
+Neo.Painter.TOOLTYPE_BLUR = 17;
+Neo.Painter.TOOLTYPE_DODGE = 18;
+Neo.Painter.TOOLTYPE_BURN = 19;
+Neo.Painter.TOOLTYPE_RECT = 20;
+Neo.Painter.TOOLTYPE_RECTFILL = 21;
+Neo.Painter.TOOLTYPE_ELLIPSE = 22;
+Neo.Painter.TOOLTYPE_ELLIPSEFILL = 23;
+Neo.Painter.TOOLTYPE_BLURRECT = 24;
+Neo.Painter.TOOLTYPE_TURN = 25;
+
+Neo.Painter.prototype.build = function(div, width, height)
+{
+ this.container = div;
+ this._initCanvas(div, width, height);
+ this._initRoundData();
+ this._initToneData();
+ this._initInputText();
+
+ this.setTool(new Neo.PenTool());
+
+};
+
+Neo.Painter.prototype.setTool = function(tool) {
+ if (this.tool && this.tool.saveStates) this.tool.saveStates();
+
+ if (this.tool && this.tool.kill) {
+ this.tool.kill();
+ }
+ this.tool = tool;
+ tool.init();
+ if (this.tool && this.tool.loadStates) this.tool.loadStates();
+};
+
+Neo.Painter.prototype.pushTool = function(tool) {
+ this.toolStack.push(this.tool);
+ this.tool = tool;
+ tool.init();
+};
+
+Neo.Painter.prototype.popTool = function() {
+ var tool = this.tool;
+ if (tool && tool.kill) {
+ tool.kill();
+ }
+ this.tool = this.toolStack.pop();
+};
+
+Neo.Painter.prototype.getCurrentTool = function() {
+ if (this.tool) {
+ var tool = this.tool;
+ if (tool && tool.type == Neo.Painter.TOOLTYPE_SLIDER) {
+ var stack = this.toolStack;
+ if (stack.length > 0) {
+ tool = stack[stack.length - 1];
+ }
+ }
+ return tool;
+ }
+ return null;
+};
+
+Neo.Painter.prototype.setToolByType = function(toolType) {
+ switch (parseInt(toolType)) {
+ case Neo.Painter.TOOLTYPE_PEN: this.setTool(new Neo.PenTool()); break;
+ case Neo.Painter.TOOLTYPE_ERASER: this.setTool(new Neo.EraserTool()); break;
+ case Neo.Painter.TOOLTYPE_HAND: this.setTool(new Neo.HandTool()); break;
+ case Neo.Painter.TOOLTYPE_FILL: this.setTool(new Neo.FillTool()); break;
+ case Neo.Painter.TOOLTYPE_ERASEALL: this.setTool(new Neo.EraseAllTool()); break;
+ case Neo.Painter.TOOLTYPE_ERASERECT: this.setTool(new Neo.EraseRectTool()); break;
+
+ case Neo.Painter.TOOLTYPE_COPY: this.setTool(new Neo.CopyTool()); break;
+ case Neo.Painter.TOOLTYPE_PASTE: this.setTool(new Neo.PasteTool()); break;
+ case Neo.Painter.TOOLTYPE_MERGE: this.setTool(new Neo.MergeTool()); break;
+ case Neo.Painter.TOOLTYPE_FLIP_H: this.setTool(new Neo.FlipHTool()); break;
+ case Neo.Painter.TOOLTYPE_FLIP_V: this.setTool(new Neo.FlipVTool()); break;
+
+ case Neo.Painter.TOOLTYPE_BRUSH: this.setTool(new Neo.BrushTool()); break;
+ case Neo.Painter.TOOLTYPE_TEXT: this.setTool(new Neo.TextTool()); break;
+ case Neo.Painter.TOOLTYPE_TONE: this.setTool(new Neo.ToneTool()); break;
+ case Neo.Painter.TOOLTYPE_BLUR: this.setTool(new Neo.BlurTool()); break;
+ case Neo.Painter.TOOLTYPE_DODGE: this.setTool(new Neo.DodgeTool()); break;
+ case Neo.Painter.TOOLTYPE_BURN: this.setTool(new Neo.BurnTool()); break;
+
+ case Neo.Painter.TOOLTYPE_RECT: this.setTool(new Neo.RectTool()); break;
+ case Neo.Painter.TOOLTYPE_RECTFILL: this.setTool(new Neo.RectFillTool()); break;
+ case Neo.Painter.TOOLTYPE_ELLIPSE: this.setTool(new Neo.EllipseTool()); break;
+ case Neo.Painter.TOOLTYPE_ELLIPSEFILL:this.setTool(new Neo.EllipseFillTool()); break;
+ case Neo.Painter.TOOLTYPE_BLURRECT: this.setTool(new Neo.BlurRectTool()); break;
+ case Neo.Painter.TOOLTYPE_TURN: this.setTool(new Neo.TurnTool()); break;
+
+ default:
+ console.log("unknown toolType " + toolType);
+ break;
+ }
+};
+
+Neo.Painter.prototype._initCanvas = function(div, width, height) {
+ width = parseInt(width);
+ height = parseInt(height);
+ var destWidth = parseInt(div.clientWidth);
+ var destHeight = parseInt(div.clientHeight);
+ this.destWidth = width;
+ this.destHeight = height;
+
+ this.canvasWidth = width;
+ this.canvasHeight = height;
+ this.zoomX = width * 0.5;
+ this.zoomY = height * 0.5;
+
+ for (var i = 0; i < 2; i++) {
+ this.canvas[i] = document.createElement("canvas");
+ this.canvas[i].width = width;
+ this.canvas[i].height = height;
+ this.canvasCtx[i] = this.canvas[i].getContext("2d");
+
+ this.canvas[i].style.imageRendering = "pixelated";
+ this.canvasCtx[i].imageSmoothingEnabled = false;
+ this.canvasCtx[i].mozImageSmoothingEnabled = false;
+ this.visible[i] = true;
+ }
+
+ this.tempCanvas = document.createElement("canvas");
+ this.tempCanvas.width = width;
+ this.tempCanvas.height = height;
+ this.tempCanvasCtx = this.tempCanvas.getContext("2d");
+ this.tempCanvas.style.position = "absolute";
+ this.tempCanvas.enabled = false;
+
+ var array = this.container.getElementsByTagName("canvas");
+ if (array.length > 0) {
+ this.destCanvas = array[0];
+ } else {
+ this.destCanvas = document.createElement("canvas");
+ this.container.appendChild(this.destCanvas);
+ }
+
+ this.destCanvasCtx = this.destCanvas.getContext("2d");
+ this.destCanvas.width = destWidth;
+ this.destCanvas.height = destHeight;
+
+ this.destCanvas.style.imageRendering = "pixelated";
+ this.destCanvasCtx.imageSmoothingEnabled = false;
+ this.destCanvasCtx.mozImageSmoothingEnabled = false;
+
+ var ref = this;
+
+ var container = document.getElementById("container");
+
+ container.onmousedown = function(e) {ref._mouseDownHandler(e)};
+ container.onmousemove = function(e) {ref._mouseMoveHandler(e)};
+ container.onmouseup = function(e) {ref._mouseUpHandler(e)};
+ container.onmouseover = function(e) {ref._rollOverHandler(e)};
+ container.onmouseout = function(e) {ref._rollOutHandler(e)};
+ container.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ }, false);
+ container.addEventListener("touchmove", function(e) {
+ ref._mouseMoveHandler(e);
+ }, false);
+ container.addEventListener("touchend", function(e) {
+ ref._mouseUpHandler(e);
+ }, false);
+
+ document.onkeydown = function(e) {ref._keyDownHandler(e)};
+ document.onkeyup = function(e) {ref._keyUpHandler(e)};
+
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype._initRoundData = function() {
+ for (var r = 1; r <= 30; r++) {
+ this._roundData[r] = new Uint8Array(r * r);
+ var mask = this._roundData[r];
+ var d = Math.floor(r / 2.0);
+ var index = 0;
+ for (var x = 0; x < r; x++) {
+ for (var y = 0; y < r; y++) {
+ var xx = x + 0.5 - r/2.0;
+ var yy = y + 0.5 - r/2.0;
+ mask[index++] = (xx*xx + yy*yy <= r*r/4) ? 1 : 0;
+ }
+ }
+ }
+ this._roundData[3][0] = 0;
+ this._roundData[3][2] = 0;
+ this._roundData[3][6] = 0;
+ this._roundData[3][8] = 0;
+
+ this._roundData[5][1] = 0;
+ this._roundData[5][3] = 0;
+ this._roundData[5][5] = 0;
+ this._roundData[5][9] = 0;
+ this._roundData[5][15] = 0;
+ this._roundData[5][19] = 0;
+ this._roundData[5][21] = 0;
+ this._roundData[5][23] = 0;
+};
+
+Neo.Painter.prototype._initToneData = function() {
+ var pattern = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];
+
+ for (var i = 0; i < 16; i++) {
+ this._toneData[i] = new Uint8Array(16);
+ for (var j = 0; j < 16; j++) {
+ this._toneData[i][j] = (i >= pattern[j]) ? 1 : 0;
+ }
+ }
+};
+
+Neo.Painter.prototype.getToneData = function(alpha) {
+ var alphaTable = [23,
+ 47,
+ 69,
+ 92,
+ 114,
+ 114,
+ 114,
+ 138,
+ 161,
+ 184,
+ 184,
+ 207,
+ 230,
+ 230,
+ 253,
+ ];
+
+ for (var i = 0; i < alphaTable.length; i++) {
+ if (alpha < alphaTable[i]) {
+ return this._toneData[i];
+ }
+ }
+ return this._toneData[i];
+};
+
+Neo.Painter.prototype._initInputText = function() {
+ var text = document.getElementById("inputtext");
+ if (!text) {
+ text = document.createElement("div");
+ }
+
+ text.id = "inputext";
+ text.setAttribute("contentEditable", true);
+ text.spellcheck = false;
+ text.className = "inputText";
+ text.innerHTML = "";
+
+ text.style.display = "none";
+// text.style.userSelect = "none";
+ Neo.painter.container.appendChild(text);
+ this.inputText = text;
+
+ this.updateInputText();
+};
+
+Neo.Painter.prototype.hideInputText = function() {
+ var text = this.inputText;
+ text.blur();
+ text.style.display = "none";
+};
+
+Neo.Painter.prototype.updateInputText = function() {
+ var text = this.inputText;
+ var d = this.lineWidth;
+ var fontSize = Math.round(d * 55/28 + 7);
+ var height = Math.round(d * 68/28 + 12);
+
+ text.style.fontSize = fontSize + "px";
+ text.style.lineHeight = fontSize + "px";
+ text.style.height = fontSize + "px";
+ text.style.marginTop = -fontSize + "px";
+};
+
+/*
+-----------------------------------------------------------------------
+ Mouse Event Handling
+-----------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype._keyDownHandler = function(e) {
+ this.isShiftDown = e.shiftKey;
+ this.isCtrlDown = e.ctrlKey;
+ this.isAltDown = e.altKey;
+ if (e.keyCode == 32) this.isSpaceDown = true;
+
+ if (!this.isShiftDown && this.isCtrlDown) {
+ if (!this.isAltDown) {
+ if (e.keyCode == 90 || e.keyCode == 85) this.undo(); //Ctrl+Z,Ctrl.U
+ if (e.keyCode == 89) this.redo(); //Ctrl+Y
+ } else {
+ if (e.keyCode == 90) this.redo(); //Ctrl+Alt+Z
+ }
+ }
+
+ if (!this.isShiftDown && !this.isCtrlDown && !this.isAltDown) {
+ if (e.keyCode == 107) new Neo.ZoomPlusCommand(this).execute(); // +
+ if (e.keyCode == 109) new Neo.ZoomMinusCommand(this).execute(); // -
+ }
+
+ if (this.tool.keyDownHandler) {
+ this.tool.keyDownHandler(e);
+ }
+
+ //スペース・Shift+スペースででスクロールしないように
+ if (document.activeElement != this.inputText) e.preventDefault();
+};
+
+Neo.Painter.prototype._keyUpHandler = function(e) {
+ this.isShiftDown = e.shiftKey;
+ this.isCtrlDown = e.ctrlKey;
+ this.isAltDown = e.altKey;
+ if (e.keyCode == 32) this.isSpaceDown = false;
+
+ if (this.tool.keyUpHandler) {
+ this.tool.keyUpHandler(oe);
+ }
+};
+
+Neo.Painter.prototype._rollOverHandler = function(e) {
+ if (this.tool.rollOverHandler) {
+ this.tool.rollOverHandler(this);
+ }
+};
+
+Neo.Painter.prototype._rollOutHandler = function(e) {
+ if (this.tool.rollOutHandler) {
+ this.tool.rollOutHandler(this);
+ }
+};
+
+Neo.Painter.prototype._mouseDownHandler = function(e) {
+ if (e.target == Neo.painter.destCanvas) {
+ //よくわからないがChromeでドラッグの時カレットが出るのを防ぐ
+ //http://stackoverflow.com/questions/2745028/chrome-sets-cursor-to-text-while-dragging-why
+ e.preventDefault();
+ }
+
+ if (e.type == "touchstart" && e.touches.length > 1) return;
+
+ if (e.button == 2 || this.virtualRight) {
+ this.isMouseDownRight = true;
+
+ } else {
+ if (!e.shiftKey && e.ctrlKey && e.altKey) {
+ this.isMouseDown = true;
+
+ } else {
+ if (e.ctrlKey || e.altKey) {
+ this.isMouseDownRight = true;
+ } else {
+ this.isMouseDown = true;
+ }
+ }
+ }
+
+ this._updateMousePosition(e);
+ this.prevMouseX = this.mouseX;
+ this.prevMouseY = this.mouseY;
+
+ if (this.isMouseDownRight) {
+ this.isMouseDownRight = false;
+ if (!this.isWidget(e.target)) {
+ this.pickColor(this.mouseX, this.mouseY);
+ return;
+ }
+ }
+
+ if (!this.isUIPaused()) {
+ if (e.target['data-bar']) {
+ this.pushTool(new Neo.HandTool());
+
+ } else if (this.isSpaceDown && document.activeElement != this.inputText) {
+ this.pushTool(new Neo.HandTool());
+ this.tool.reverse = true;
+
+ } else if (e.target['data-slider'] != undefined) {
+ this.pushTool(new Neo.SliderTool());
+ this.tool.target = e.target;
+
+ } else if (e.ctrlKey && e.altKey && !e.shiftKey) {
+ this.pushTool(new Neo.SliderTool());
+ this.tool.target = Neo.sliders[Neo.SLIDERTYPE_SIZE].element;
+ this.tool.alt = true;
+
+ } else if (this.isWidget(e.target)) {
+ this.isMouseDown = false;
+ this.pushTool(new Neo.DummyTool());
+
+ }
+ }
+
+// console.warn("down -" + e.target.id + e.target.className)
+ if (!(e.target.className == "o" && e.type == "touchdown")) {
+ this.tool.downHandler(this);
+ }
+
+// var ref = this;
+// document.onmouseup = function(e) {
+// ref._mouseUpHandler(e)
+// };
+};
+
+Neo.Painter.prototype._mouseUpHandler = function(e) {
+ this.isMouseDown = false;
+ this.isMouseDownRight = false;
+ this.tool.upHandler(this);
+// document.onmouseup = undefined;
+
+ if (e.target.id != "right") {
+ this.virtualRight = false;
+ Neo.RightButton.clear();
+ }
+
+// if (e.changedTouches) {
+// for (var i = 0; i < e.changedTouches.length; i++) {
+// var touch = e.changedTouches[i];
+// if (touch.identifier == this.touchModifier) {
+// this.touchModifier = null;
+// }
+// }
+// }
+};
+
+Neo.Painter.prototype._mouseMoveHandler = function(e) {
+ this._updateMousePosition(e);
+
+ if (e.type == "touchmove" && e.touches.length > 1) return;
+
+ if (this.isMouseDown || this.isMouseDownRight) {
+ this.tool.moveHandler(this);
+
+ } else {
+ if (this.tool.upMoveHandler) {
+ this.tool.upMoveHandler(this);
+ }
+ }
+
+ this.prevMouseX = this.mouseX;
+ this.prevMouseY = this.mouseY;
+
+ // 画面外をタップした時スクロール可能にするため
+// console.warn("move -" + e.target.id + e.target.className)
+ if (!(e.target.className == "o" && e.type == "touchmove")) {
+ e.preventDefault();
+ }
+};
+
+
+Neo.Painter.prototype.getPosition = function(e) {
+ if (e.clientX !== undefined) {
+ return {x: e.clientX, y: e.clientY, e: e.type};
+
+ } else {
+ var touch = e.changedTouches[0];
+ return {x: touch.clientX, y: touch.clientY, e: e.type};
+
+// for (var i = 0; i < e.changedTouches.length; i++) {
+// var touch = e.changedTouches[i];
+// if (!this.touchModifier || this.touchModifier != touch.identifier) {
+// return {x: touch.clientX, y: touch.clientY, e: e.type};
+// }
+// }
+// console.log("getPosition error");
+// return {x:0, y:0};
+ }
+}
+
+Neo.Painter.prototype._updateMousePosition = function(e) {
+ var rect = this.destCanvas.getBoundingClientRect();
+// var x = (e.clientX !== undefined) ? e.clientX : e.touches[0].clientX;
+// var y = (e.clientY !== undefined) ? e.clientY : e.touches[0].clientY;
+ var pos = this.getPosition(e);
+ var x = pos.x;
+ var y = pos.y;
+
+ if (this.zoom <= 0) this.zoom = 1; //なぜか0になることがあるので
+
+ this.mouseX = (x - rect.left) / this.zoom
+ + this.zoomX
+ - this.destCanvas.width * 0.5 / this.zoom;
+ this.mouseY = (y - rect.top) / this.zoom
+ + this.zoomY
+ - this.destCanvas.height * 0.5 / this.zoom;
+
+ if (isNaN(this.prevMouseX)) {
+ this.prevMouseX = this.mouseX;
+ }
+ if (isNaN(this.prevMouseY)) {
+ this.prevMosueY = this.mouseY;
+ }
+
+ this.slowX = this.slowX * 0.8 + this.mouseX * 0.2;
+ this.slowY = this.slowY * 0.8 + this.mouseY * 0.2;
+ var now = new Date().getTime();
+ if (this.stab) {
+ var pause = this.stab[3];
+ if (pause) {
+ // ポーズ中
+ if (now > pause) {
+ this.stab = [this.slowX, this.slowY, now];
+ }
+
+ } else {
+ // ポーズされていないとき
+ var prev = this.stab[2];
+ if (now - prev > 150) { // 150ms以上止まっていたらポーズをオンにする
+ this.stab[3] = now + 200 // 200msペンの位置を固定
+
+ } else {
+ this.stab = [this.slowX, this.slowY, now];
+ }
+ }
+ } else {
+ this.stab = [this.slowX, this.slowY, now];
+ }
+
+ this.rawMouseX = x;
+ this.rawMouseY = y;
+ this.clipMouseX = Math.max(Math.min(this.canvasWidth, this.mouseX), 0);
+ this.clipMouseY = Math.max(Math.min(this.canvasHeight, this.mouseY), 0);
+};
+
+Neo.Painter.prototype._beforeUnloadHandler = function(e) {
+ // quick save
+};
+
+Neo.Painter.prototype.getStabilized = function() {
+ return this.stab;
+};
+
+/*
+-------------------------------------------------------------------------
+ Undo
+-------------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.undo = function() {
+ var undoItem = this._undoMgr.popUndo();
+ if (undoItem) {
+ this._pushRedo();
+ this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y);
+ this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y);
+ this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height);
+ }
+};
+
+Neo.Painter.prototype.redo = function() {
+ var undoItem = this._undoMgr.popRedo();
+ if (undoItem) {
+ this._pushUndo(0,0,this.canvasWidth, this.canvasHeight, true);
+ this.canvasCtx[0].putImageData(undoItem.data[0], undoItem.x,undoItem.y);
+ this.canvasCtx[1].putImageData(undoItem.data[1], undoItem.x,undoItem.y);
+ this.updateDestCanvas(undoItem.x, undoItem.y, undoItem.width, undoItem.height);
+ }
+};
+
+Neo.Painter.prototype.hasUndo = function() {
+ return true;
+};
+
+Neo.Painter.prototype._pushUndo = function(x, y, w, h, holdRedo) {
+ x = (x === undefined) ? 0 : x;
+ y = (y === undefined) ? 0 : y;
+ w = (w === undefined) ? this.canvasWidth : w;
+ h = (h === undefined) ? this.canvasHeight : h;
+ var undoItem = new Neo.UndoItem();
+ undoItem.x = 0;
+ undoItem.y = 0;
+ undoItem.width = w;
+ undoItem.height = h;
+ undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h),
+ this.canvasCtx[1].getImageData(x, y, w, h)];
+ this._undoMgr.pushUndo(undoItem, holdRedo);
+};
+
+Neo.Painter.prototype._pushRedo = function(x, y, w, h) {
+ x = (x === undefined) ? 0 : x;
+ y = (y === undefined) ? 0 : y;
+ w = (w === undefined) ? this.canvasWidth : w;
+ h = (h === undefined) ? this.canvasHeight : h;
+ var undoItem = new Neo.UndoItem();
+ undoItem.x = 0;
+ undoItem.y = 0;
+ undoItem.width = w;
+ undoItem.height = h;
+ undoItem.data = [this.canvasCtx[0].getImageData(x, y, w, h),
+ this.canvasCtx[1].getImageData(x, y, w, h)];
+ this._undoMgr.pushRedo(undoItem);
+};
+
+
+/*
+-------------------------------------------------------------------------
+ Data Cache for Undo / Redo
+-------------------------------------------------------------------------
+*/
+
+Neo.UndoManager = function(_maxStep){
+ this._maxStep = _maxStep;
+ this._undoItems = [];
+ this._redoItems = [];
+}
+Neo.UndoManager.prototype._maxStep;
+Neo.UndoManager.prototype._redoItems;
+Neo.UndoManager.prototype._undoItems;
+
+//アクションをしてUndo情報を更新
+Neo.UndoManager.prototype.pushUndo = function(undoItem, holdRedo) {
+ this._undoItems.push(undoItem);
+ if (this._undoItems.length > this._maxStep) {
+ this._undoItems.shift();
+ }
+
+ if (!holdRedo == true) {
+ this._redoItems = [];
+ }
+};
+
+Neo.UndoManager.prototype.popUndo = function() {
+ return this._undoItems.pop();
+}
+
+Neo.UndoManager.prototype.pushRedo = function(undoItem) {
+ this._redoItems.push(undoItem);
+}
+
+Neo.UndoManager.prototype.popRedo = function() {
+ return this._redoItems.pop();
+}
+
+
+Neo.UndoItem = function() {}
+Neo.UndoItem.prototype.data;
+Neo.UndoItem.prototype.x;
+Neo.UndoItem.prototype.y;
+Neo.UndoItem.prototype.width;
+Neo.UndoItem.prototype.height;
+
+/*
+-------------------------------------------------------------------------
+ Zoom Controller
+-------------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.setZoom = function(value) {
+ this.zoom = value;
+
+ var container = document.getElementById("container");
+ var width = this.canvasWidth * this.zoom;
+ var height = this.canvasHeight * this.zoom;
+ if (width > container.clientWidth - 100) width = container.clientWidth - 100;
+ if (height > container.clientHeight - 130) height = container.clientHeight - 130;
+ this.destWidth = width;
+ this.destHeight = height;
+
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight, false);
+ this.setZoomPosition(this.zoomX, this.zoomY);
+};
+
+Neo.Painter.prototype.setZoomPosition = function(x, y) {
+ var minx = (this.destCanvas.width / this.zoom) * 0.5;
+ var maxx = this.canvasWidth - minx;
+ var miny = (this.destCanvas.height / this.zoom) * 0.5;
+ var maxy = this.canvasHeight - miny;
+
+
+ x = Math.round(Math.max(Math.min(maxx,x),minx));
+ y = Math.round(Math.max(Math.min(maxy,y),miny));
+
+ this.zoomX = x;
+ this.zoomY = y;
+ this.updateDestCanvas(0,0,this.canvasWidth,this.canvasHeight,false);
+
+ this.scrollBarX = (maxx == minx) ? 0 : (x - minx) / (maxx - minx);
+ this.scrollBarY = (maxy == miny) ? 0 : (y - miny) / (maxy - miny);
+ this.scrollWidth = maxx - minx;
+ this.scrollHeight = maxy - miny;
+
+ if (Neo.scrollH) Neo.scrollH.update(this);
+ if (Neo.scrollV) Neo.scrollV.update(this);
+
+ this.hideInputText();
+};
+
+
+/*
+-------------------------------------------------------------------------
+ Drawing Helper
+-------------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.submit = function(board) {
+ var thumbnail = null;
+ var thumbnail2 = null;
+
+ if (this.useThumbnail()) {
+ thumbnail = this.getThumbnail(Neo.config.thumbnail_type || "png");
+ if (Neo.config.thumbnail_type2) {
+ thumbnail2 = this.getThumbnail(Neo.config.thumbnail_type2);
+ }
+ }
+ Neo.submit(board, this.getPNG(), thumbnail2, thumbnail);
+};
+
+Neo.Painter.prototype.useThumbnail = function() {
+ var thumbnailWidth = this.getThumbnailWidth();
+ var thumbnailHeight = this.getThumbnailHeight();
+ if (thumbnailWidth && thumbnailHeight) {
+ if (thumbnailWidth < this.canvasWidth ||
+ thumbnailHeight < this.canvasHeight) {
+ return true;
+ }
+ }
+ return false;
+};
+
+Neo.Painter.prototype.dataURLtoBlob = function(dataURL) {
+ var byteString;
+ if (dataURL.split(',')[0].indexOf('base64') >= 0) {
+ byteString = atob(dataURL.split(',')[1]);
+ } else {
+ byteString = unescape(dataURL.split(',')[1]);
+ }
+
+ // write the bytes of the string to a typed array
+ var ia = new Uint8Array(byteString.length);
+ for (var i = 0; i < byteString.length; i++) {
+ ia[i] = byteString.charCodeAt(i);
+ }
+ return new Blob([ia], {type:'image/png'});
+};
+
+Neo.Painter.prototype.getImage = function(imageWidth, imageHeight) {
+ var width = this.canvasWidth;
+ var height = this.canvasHeight;
+ imageWidth = imageWidth || width;
+ imageHeight = imageHeight || height;
+
+ var pngCanvas = document.createElement("canvas");
+ pngCanvas.width = imageWidth;
+ pngCanvas.height = imageHeight;
+ var pngCanvasCtx = pngCanvas.getContext("2d");
+ pngCanvasCtx.fillStyle = "#ffffff";
+ pngCanvasCtx.fillRect(0, 0, imageWidth, imageHeight);
+
+ if (this.visible[0]) {
+ pngCanvasCtx.drawImage(this.canvas[0],
+ 0, 0, width, height,
+ 0, 0, imageWidth, imageHeight);
+ }
+ if (this.visible[1]) {
+ pngCanvasCtx.drawImage(this.canvas[1],
+ 0, 0, width, height,
+ 0, 0, imageWidth, imageHeight);
+ }
+ return pngCanvas;
+};
+
+Neo.Painter.prototype.getPNG = function() {
+ var image = this.getImage();
+ var dataURL = image.toDataURL('image/png');
+ return this.dataURLtoBlob(dataURL);
+};
+
+Neo.Painter.prototype.getThumbnail = function(type) {
+ if (type != "animation") {
+ var thumbnailWidth = this.getThumbnailWidth();
+ var thumbnailHeight = this.getThumbnailHeight();
+ if (thumbnailWidth || thumbnailHeight) {
+ var width = this.canvasWidth;
+ var height = this.canvasHeight;
+ if (thumbnailWidth == 0) {
+ thumbnailWidth = thumbnailHeight * width / height;
+ }
+ if (thumbnailHeight == 0) {
+ thumbnailHeight = thumbnailWidth * height / width;
+ }
+ } else {
+ thumbnailWidth = thumbnailHeight = null;
+ }
+
+ console.log("get thumbnail", thumbnailWidth, thumbnailHeight);
+
+ var image = this.getImage(thumbnailWidth, thumbnailHeight);
+ var dataURL = image.toDataURL('image/' + type);
+ return this.dataURLtoBlob(dataURL);
+
+ } else {
+ return new Blob([]); //animationには対応していないのでダミーデータを返す
+ }
+};
+
+Neo.Painter.prototype.getThumbnailWidth = function() {
+ var width = Neo.config.thumbnail_width;
+ if (width) {
+ if (width.match(/%$/)) {
+ return Math.floor(this.canvasWidth * (parseInt(width) / 100.0));
+ } else {
+ return parseInt(width);
+ }
+ }
+ return 0;
+};
+
+Neo.Painter.prototype.getThumbnailHeight = function() {
+ var height = Neo.config.thumbnail_height;
+ if (height) {
+ if (height.match(/%$/)) {
+ return Math.floor(this.canvasHeight * (parseInt(height) / 100.0));
+ } else {
+ return parseInt(height);
+ }
+ }
+ return 0;
+};
+
+Neo.Painter.prototype.clearCanvas = function(doConfirm) {
+ if (!doConfirm || confirm("全消しします")) {
+ //Register undo first;
+ this._pushUndo();
+
+ this.canvasCtx[0].clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+ this.canvasCtx[1].clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight);
+ }
+};
+
+Neo.Painter.prototype.updateDestCanvas = function(x, y, width, height, useTemp) {
+ var canvasWidth = this.canvasWidth;
+ var canvasHeight = this.canvasHeight;
+ var updateAll = false;
+ if (x == 0 && y == 0 && width == canvasWidth && height == canvasHeight) {
+ updateAll = true;
+ };
+
+ if (x + width > this.canvasWidth) width = this.canvasWidth - x;
+ if (y + height > this.canvasHeight) height = this.canvasHeight - y;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (width <= 0 || height <= 0) return;
+
+ var ctx = this.destCanvasCtx;
+ ctx.save();
+ ctx.fillStyle = "#ffffff";
+
+ var fillWidth = width
+ var fillHeight = height
+
+ if (updateAll) {
+ ctx.fillRect(0, 0, this.destCanvas.width, this.destCanvas.height);
+
+ } else {
+ //カーソルの描画ゴミが残るのをごまかすため
+ if (x + width == this.canvasWidth) fillWidth = width + 1;
+ if (y + height == this.canvasHeight) fillHeight = height + 1;
+ }
+
+ ctx.translate(this.destCanvas.width*.5, this.destCanvas.height*.5);
+ ctx.scale(this.zoom, this.zoom);
+ ctx.translate(-this.zoomX, -this.zoomY);
+ ctx.globalAlpha = 1.0;
+ ctx.msImageSmoothingEnabled = 0;
+
+ if (!updateAll) {
+ ctx.fillRect(x, y, fillWidth, fillHeight);
+ }
+
+ if (this.visible[0]) {
+ ctx.drawImage(this.canvas[0],
+ x, y, width, height,
+ x, y, width, height);
+ }
+ if (this.visible[1]) {
+ ctx.drawImage(this.canvas[1],
+ x, y, width, height,
+ x, y, width, height);
+ }
+ if (useTemp) {
+ ctx.globalAlpha = 1.0; //this.alpha;
+ ctx.drawImage(this.tempCanvas,
+ x, y, width, height,
+ x + this.tempX, y + this.tempY, width, height);
+ }
+ ctx.restore();
+};
+
+Neo.Painter.prototype.getBound = function(x0, y0, x1, y1, r) {
+ var left = Math.floor((x0 < x1) ? x0 : x1);
+ var top = Math.floor((y0 < y1) ? y0 : y1);
+ var width = Math.ceil(Math.abs(x0 - x1));
+ var height = Math.ceil(Math.abs(y0 - y1));
+ r = Math.ceil(r + 1);
+
+ if (!r) {
+ width += 1;
+ height += 1;
+
+ } else {
+ left -= r;
+ top -= r;
+ width += r * 2;
+ height += r * 2;
+ }
+ return [left, top, width, height];
+};
+
+Neo.Painter.prototype.getColor = function(c) {
+ if (!c) c = this.foregroundColor;
+ var r = parseInt(c.substr(1, 2), 16);
+ var g = parseInt(c.substr(3, 2), 16);
+ var b = parseInt(c.substr(5, 2), 16);
+ var a = Math.floor(this.alpha * 255);
+ return a <<24 | b<<16 | g<<8 | r;
+};
+
+Neo.Painter.prototype.getColorString = function(c) {
+ var rgb = ("000000" + (c & 0xffffff).toString(16)).substr(-6);
+ return '#' + rgb;
+};
+
+Neo.Painter.prototype.setColor = function(c) {
+ if (typeof c != "string") c = this.getColorString(c);
+ this.foregroundColor = c;
+
+ Neo.updateUI();
+};
+
+Neo.Painter.prototype.getAlpha = function(type) {
+ var a1 = this.alpha;
+
+ switch (type) {
+ case Neo.Painter.ALPHATYPE_PEN:
+ if (a1 > 0.5) {
+ a1 = 1.0/16 + (a1 - 0.5) * 30.0/16;
+ } else {
+ a1 = Math.sqrt(2 * a1) / 16.0;
+ }
+ a1 = Math.min(1, Math.max(0, a1));
+ break;
+
+ case Neo.Painter.ALPHATYPE_FILL:
+ a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042;
+ a1 = Math.min(1.0, Math.max(0, a1 * 10));
+ break;
+
+ case Neo.Painter.ALPHATYPE_BRUSH:
+ a1 = -0.00056 * a1 + 0.0042 / (1.0 - a1) - 0.0042;
+ a1 = Math.min(1.0, Math.max(0, a1));
+ break;
+ }
+
+ // アルファが小さい時は適当に点を抜いて見た目の濃度を合わせる
+ if (a1 < 1.0/255) {
+ this.aerr += a1;
+ a1 = 0;
+ while (this.aerr > 1.0/255) {
+ a1 = 1.0/255;
+ this.aerr -= 1.0/255;
+ }
+ }
+ return a1;
+};
+
+Neo.Painter.prototype.prepareDrawing = function () {
+ var r = parseInt(this.foregroundColor.substr(1, 2), 16);
+ var g = parseInt(this.foregroundColor.substr(3, 2), 16);
+ var b = parseInt(this.foregroundColor.substr(5, 2), 16);
+ var a = Math.floor(this.alpha * 255);
+
+ var maskR = parseInt(this.maskColor.substr(1, 2), 16);
+ var maskG = parseInt(this.maskColor.substr(3, 2), 16);
+ var maskB = parseInt(this.maskColor.substr(5, 2), 16);
+
+ this._currentColor = [r, g, b, a];
+ this._currentMask = [maskR, maskG, maskB];
+};
+
+Neo.Painter.prototype.isMasked = function (buf8, index) {
+ var r = this._currentMask[0];
+ var g = this._currentMask[1];
+ var b = this._currentMask[2];
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3];
+
+ if (a0 == 0) {
+ r0 = 0xff;
+ g0 = 0xff;
+ b0 = 0xff;
+ }
+
+ var type = this.maskType;
+
+ //TODO
+ //いろいろ試したのですが半透明で描画するときの加算・逆加算を再現する方法がわかりません。
+ //とりあえず単純に無視しています。
+ if (type == Neo.Painter.MASKTYPE_ADD ||
+ type == Neo.Painter.MASKTYPE_SUB) {
+ if (this._currentColor[3] < 250) {
+ type = Neo.Painter.MASKTYPE_NONE;
+ }
+ }
+
+ switch (type) {
+ case Neo.Painter.MASKTYPE_NONE:
+ return;
+
+ case Neo.Painter.MASKTYPE_NORMAL:
+ return (r0 == r &&
+ g0 == g &&
+ b0 == b) ? true : false;
+
+ case Neo.Painter.MASKTYPE_REVERSE:
+ return (r0 != r ||
+ g0 != g ||
+ b0 != b) ? true : false;
+
+ case Neo.Painter.MASKTYPE_ADD:
+ if (a0 > 0) {
+ var sort = this.sortColor(r0, g0, b0);
+ for (var i = 0; i < 3; i++) {
+ var c = sort[i];
+ if (buf8[index + c] < this._currentColor[c]) return true;
+ }
+ return false;
+
+ } else {
+ return false;
+ }
+
+ case Neo.Painter.MASKTYPE_SUB:
+ if (a0 > 0) {
+ var sort = this.sortColor(r0, g0, b0);
+ for (var i = 0; i < 3; i++) {
+ var c = sort[i];
+ if (buf8[index + c] > this._currentColor[c]) return true;
+ }
+ return false;
+ } else {
+ return true;
+ }
+ }
+};
+
+Neo.Painter.prototype.setPoint = function(buf8, bufWidth, x0, y0, left, top, type) {
+ var x = x0 - left;
+ var y = y0 - top;
+
+ switch (type) {
+ case Neo.Painter.LINETYPE_PEN:
+ this.setPenPoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_BRUSH:
+ this.setBrushPoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_TONE:
+ this.setTonePoint(buf8, bufWidth, x, y, x0, y0);
+ break;
+
+ case Neo.Painter.LINETYPE_ERASER:
+ this.setEraserPoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_BLUR:
+ this.setBlurPoint(buf8, bufWidth, x, y, x0, y0);
+ break;
+
+ case Neo.Painter.LINETYPE_DODGE:
+ this.setDodgePoint(buf8, bufWidth, x, y);
+ break;
+
+ case Neo.Painter.LINETYPE_BURN:
+ this.setBurnPoint(buf8, bufWidth, x, y);
+ break;
+
+ default:
+ break;
+ }
+};
+
+
+Neo.Painter.prototype.setPenPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_PEN);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+ if (a > 0) {
+ var a1x = Math.max(a1, 1.0/255);
+
+ var r = (r1 * a1x + r0 * a0 * (1 - a1x)) / a;
+ var g = (g1 * a1x + g0 * a0 * (1 - a1x)) / a;
+ var b = (b1 * a1x + b0 * a0 * (1 - a1x)) / a;
+
+ r = (r1 > r0) ? Math.ceil(r) : Math.floor(r);
+ g = (g1 > g0) ? Math.ceil(g) : Math.floor(g);
+ b = (b1 > b0) ? Math.ceil(b) : Math.floor(b);
+ }
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setBrushPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+ if (a > 0) {
+ var a1x = Math.max(a1, 1.0/255);
+
+ var r = (r1 * a1x + r0 * a0) / (a0 + a1x);
+ var g = (g1 * a1x + g0 * a0) / (a0 + a1x);
+ var b = (b1 * a1x + b0 * a0) / (a0 + a1x);
+
+ r = (r1 > r0) ? Math.ceil(r) : Math.floor(r);
+ g = (g1 > g0) ? Math.ceil(g) : Math.floor(g);
+ b = (b1 > b0) ? Math.ceil(b) : Math.floor(b);
+ }
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setTonePoint = function(buf8, width, x, y, x0, y0) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+
+ x -= r0;
+ y -= r0;
+ x0 -= r0;
+ y0 -= r0;
+// x -= r0;
+// y -= r0;
+// if (r0%2) { x0++; y0++; } //なぜか模様がずれるので
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+ var index = (y * width + x) * 4;
+
+ var r = this._currentColor[0];
+ var g = this._currentColor[1];
+ var b = this._currentColor[2];
+ var a = this._currentColor[3];
+
+ var toneData = this.getToneData(a);
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ if (toneData[((y0+i)%4) + (((x0+j)%4) * 4)]) {
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = 255;
+ }
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setEraserPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+ var index = (y * width + x) * 4;
+ var a = Math.floor(this.alpha * 255);
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var k = (buf8[index + 3] / 255.0) * (1.0 - (a / 255.0));
+
+ buf8[index + 3] -= a / (d * (255.0 - a) / 255.0);
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setBlurPoint = function(buf8, width, x, y, x0, y0) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+ var height = buf8.length / (width * 4);
+
+// var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ var a1 = this.alpha / 12;
+ if (a1 == 0) return;
+ var blur = a1;
+
+ var tmp = new Uint8ClampedArray(buf8.length);
+ for (var i = 0; i < buf8.length; i++) {
+ tmp[i] = buf8[i];
+ }
+
+ var left = x0 - x - r0;
+ var top = y0 - y - r0;
+
+ var xstart = 0, xend = d;
+ var ystart = 0, yend = d;
+ if (xstart > left) xstart = -left;
+ if (ystart > top) ystart = -top;
+ if (xend > this.canvasWidth - left) xend = this.canvasWidth - left;
+ if (yend > this.canvasHeight - top) yend = this.canvasHeight - top;
+
+ for (var j = ystart; j < yend; j++) {
+ var index = (j * width + xstart) * 4;
+ for (var i = xstart; i < xend; i++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var rgba = [0, 0, 0, 0, 0];
+
+ this.addBlur(tmp, index, 1.0 - blur*4, rgba);
+ if (i > xstart) this.addBlur(tmp, index - 4, blur, rgba);
+ if (i < xend - 1) this.addBlur(tmp, index + 4, blur, rgba);
+ if (j > ystart) this.addBlur(tmp, index - width*4, blur, rgba);
+ if (j < yend - 1) this.addBlur(tmp, index + width*4, blur, rgba);
+
+ buf8[index + 0] = Math.round(rgba[0]);
+ buf8[index + 1] = Math.round(rgba[1]);
+ buf8[index + 2] = Math.round(rgba[2]);
+ buf8[index + 3] = Math.round((rgba[3] / rgba[4]) * 255.0);
+ }
+ index += 4;
+ }
+ }
+};
+
+Neo.Painter.prototype.setDodgePoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ if (a1 != 255.0) {
+ var r1 = r0 * 255 / (255 - a1);
+ var g1 = g0 * 255 / (255 - a1);
+ var b1 = b0 * 255 / (255 - a1);
+ } else {
+ var r1 = 255.0;
+ var g1 = 255.0;
+ var b1 = 255.0;
+ }
+
+ var r = Math.ceil(r1);
+ var g = Math.ceil(g1);
+ var b = Math.ceil(b1);
+ var a = a0;
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+Neo.Painter.prototype.setBurnPoint = function(buf8, width, x, y) {
+ var d = this.lineWidth;
+ var r0 = Math.floor(d / 2);
+ x -= r0;
+ y -= r0;
+
+ var index = (y * width + x) * 4;
+
+ var shape = this._roundData[d];
+ var shapeIndex = 0;
+
+ var a1 = this.getAlpha(Neo.Painter.ALPHATYPE_BRUSH);
+ if (a1 == 0) return;
+
+ for (var i = 0; i < d; i++) {
+ for (var j = 0; j < d; j++) {
+ if (shape[shapeIndex++] && !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ if (a1 != 255.0) {
+ var r1 = 255 - (255 - r0) * 255 / (255 - a1);
+ var g1 = 255 - (255 - g0) * 255 / (255 - a1);
+ var b1 = 255 - (255 - b0) * 255 / (255 - a1);
+ } else {
+ var r1 = 0;
+ var g1 = 0;
+ var b1 = 0;
+ }
+
+ var r = Math.floor(r1);
+ var g = Math.floor(g1);
+ var b = Math.floor(b1);
+ var a = a0;
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ }
+ index += 4;
+ }
+ index += (width - d) * 4;
+ }
+};
+
+//////////////////////////////////////////////////////////////////////
+
+Neo.Painter.prototype.xorPixel = function(buf32, bufWidth, x, y, c) {
+ var index = y * bufWidth + x;
+ if (!c) c = 0xffffff;
+ buf32[index] ^= c;
+};
+
+Neo.Painter.prototype.getBezierPoint = function(t, x0, y0, x1, y1, x2, y2, x3, y3) {
+ var a0 = (1 - t) * (1 - t) * (1 - t);
+ var a1 = (1 - t) * (1 - t) * t * 3;
+ var a2 = (1 - t) * t * t * 3;
+ var a3 = t * t * t;
+
+ var x = x0 * a0 + x1 * a1 + x2 * a2 + x3 * a3;
+ var y = y0 * a0 + y1 * a1 + y2 * a2 + y3 * a3;
+ return [x, y];
+};
+
+var nmax = 1;
+
+Neo.Painter.prototype.drawBezier = function(ctx, x0, y0, x1, y1, x2, y2, x3, y3, type) {
+ var xmax = Math.max(x0, x1, x2, x3);
+ var xmin = Math.min(x0, x1, x2, x3);
+ var ymax = Math.max(y0, y1, y2, y3);
+ var ymin = Math.min(y0, y1, y2, y3);
+ var n = Math.ceil(((xmax - xmin) + (ymax - ymin)) * 2.5);
+
+ if (n > nmax) {
+ n = (n < nmax * 2) ? n : nmax * 2;
+ nmax = n;
+ }
+
+ for (var i = 0; i < n; i++) {
+ var t = i * 1.0 / n;
+ var p = this.getBezierPoint(t, x0, y0, x1, y1, x2, y2, x3, y3);
+ this.drawPoint(ctx, p[0], p[1], type);
+ }
+};
+
+Neo.Painter.prototype.prevLine = null; // 始点または終点が2度プロットされることがあるので
+Neo.Painter.prototype.drawLine = function(ctx, x0, y0, x1, y1, type) {
+ x0 = Math.round(x0);
+ x1 = Math.round(x1);
+ y0 = Math.round(y0);
+ y1 = Math.round(y1);
+ var prev = [x0, y0, x1, y1];
+
+ var width = Math.abs(x1 - x0);
+ var height = Math.abs(y1 - y0);
+ var r = Math.ceil(this.lineWidth / 2);
+
+ var left = ((x0 < x1) ? x0 : x1) - r;
+ var top = ((y0 < y1) ? y0 : y1) - r;
+
+ var imageData = ctx.getImageData(left, top, width + r*2, height + r*2);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var dx = width, sx = x0 < x1 ? 1 : -1;
+ var dy = height, sy = y0 < y1 ? 1 : -1;
+ var err = (dx > dy ? dx : -dy) / 2;
+ this.aerr = 0;
+
+ while (true) {
+ if (this.prevLine == null ||
+ !((this.prevLine[0] == x0 && this.prevLine[1] == y0) ||
+ (this.prevLine[2] == x0 && this.prevLine[3] == y0))) {
+ this.setPoint(buf8, imageData.width, x0, y0, left, top, type);
+ }
+
+ if (x0 === x1 && y0 === y1) break;
+ var e2 = err;
+ if (e2 > -dx) { err -= dy; x0 += sx; }
+ if (e2 < dy) { err += dx; y0 += sy; }
+ }
+
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, left, top);
+
+ this.prevLine = prev;
+};
+
+Neo.Painter.prototype.drawPoint = function(ctx, x, y, type) {
+ this.drawLine(ctx, x, y, x, y, type);
+};
+
+Neo.Painter.prototype.xorRect = function(buf32, bufWidth, x, y, width, height, c) {
+ var index = y * bufWidth + x;
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ buf32[index] ^= c;
+ index++;
+ }
+ index += width - bufWidth;
+ }
+};
+
+Neo.Painter.prototype.drawXORRect = function(ctx, x, y, width, height, isFill, c) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+ if (width == 0 || height == 0) return;
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var index = 0;
+ if (!c) c = 0xffffff;
+
+ if (isFill) {
+ this.xorRect(buf32, width, 0, 0, width, height, c);
+
+ } else {
+ for (var i = 0; i < width; i++) { //top
+ buf32[index] = buf32[index] ^= c;
+ index++;
+ }
+ if (height > 1) {
+ index = width;
+ for (var i = 1; i < height; i++) { //left
+ buf32[index] = buf32[index] ^= c;
+ index += width;
+ }
+ if (width > 1) {
+ index = width * 2 - 1;
+ for (var i = 1; i < height - 1; i++) { //right
+ buf32[index] = buf32[index] ^= c;
+ index += width;
+ }
+ index = width * (height - 1) + 1;
+ for (var i = 1; i < width; i++) { // bottom
+ buf32[index] = buf32[index] ^= c;
+ index++;
+ }
+ }
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.drawXOREllipse = function(ctx, x, y, width, height, isFill, c) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+ if (width == 0 || height == 0) return;
+ if (!c) c = 0xffffff;
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+
+ var a = width-1, b = height-1, b1 = b&1; /* values of diameter */
+ var dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
+ var err = dx+dy+b1*a*a, e2; /* error of 1.step */
+
+ var x0 = x;
+ var y0 = y;
+ var x1 = x0+a;
+ var y1 = y0+b;
+
+ if (x0 > x1) { x0 = x1; x1 += a; }
+ if (y0 > y1) y0 = y1;
+ y0 += Math.floor((b+1)/2); y1 = y0-b1; /* starting pixel */
+ a *= 8*a; b1 = 8*b*b;
+ var ymin = y0 - 1;
+
+ do {
+ if (isFill) {
+ if (ymin < y0) {
+ this.xorRect(buf32, width, x0-x, y0 - y, x1 - x0, 1, c);
+ if (y0 != y1) {
+ this.xorRect(buf32, width, x0-x, y1 - y, x1 - x0, 1, c);
+ }
+ ymin = y0;
+ }
+ } else {
+ this.xorPixel(buf32, width, x1-x, y0-y, c);
+ if (x0 != x1) {
+ this.xorPixel(buf32, width, x0-x, y0-y, c);
+ }
+ if (y0 != y1) {
+ this.xorPixel(buf32, width, x0-x, y1-y, c);
+ if (x0 != x1) {
+ this.xorPixel(buf32, width, x1-x, y1-y, c);
+ }
+ }
+ }
+ e2 = 2*err;
+ if (e2 <= dy) { y0++; y1--; err += dy += a; } /* y step */
+ if (e2 >= dx || 2*err > dy) { x0++; x1--; err += dx += b1; } /* x step */
+ } while (x0 <= x1);
+
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.drawXORLine = function(ctx, x0, y0, x1, y1, c) {
+ x0 = Math.round(x0);
+ x1 = Math.round(x1);
+ y0 = Math.round(y0);
+ y1 = Math.round(y1);
+
+ var width = Math.abs(x1 - x0);
+ var height = Math.abs(y1 - y0);
+
+ var left = ((x0 < x1) ? x0 : x1);
+ var top = ((y0 < y1) ? y0 : y1);
+// console.log("left:"+left+" top:"+top+" width:"+width+" height:"+height);
+
+ var imageData = ctx.getImageData(left, top, width + 1, height + 1);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var dx = width, sx = x0 < x1 ? 1 : -1;
+ var dy = height, sy = y0 < y1 ? 1 : -1;
+ var err = (dx > dy ? dx : -dy) / 2;
+
+ while (true) {
+ if (this.prevLine == null ||
+ !((this.prevLine[0] == x0 && this.prevLine[1] == y0) ||
+ (this.prevLine[2] == x0 && this.prevLine[3] == y0))) {
+
+ this.xorPixel(buf32, imageData.width, x0 - left, y0 - top, c);
+ }
+
+ if (x0 === x1 && y0 === y1) break;
+ var e2 = err;
+ if (e2 > -dx) { err -= dy; x0 += sx; }
+ if (e2 < dy) { err += dx; y0 += sy; }
+ }
+
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, left, top);
+};
+
+
+Neo.Painter.prototype.eraseRect = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var index = 0;
+
+ var a = 1.0 - this.alpha;
+ if (a != 0) {
+ a = Math.ceil(2.0 / a);
+ } else {
+ a = 255;
+ }
+
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ if (!this.isMasked(buf8, index)) {
+ buf8[index + 3] -= a;
+ }
+ index += 4;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.flipH = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var half = Math.floor(width / 2);
+ for (var j = 0; j < height; j++) {
+ var index = j * width;
+ var index2 = index + (width - 1);
+ for (var i = 0; i < half; i++) {
+ var value = buf32[index + i];
+ buf32[index + i] = buf32[index2 -i];
+ buf32[index2 - i] = value;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.flipV = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var half = Math.floor(height / 2);
+ for (var j = 0; j < half; j++) {
+ var index = j * width;
+ var index2 = (height - 1 - j) * width;
+ for (var i = 0; i < width; i++) {
+ var value = buf32[index + i];
+ buf32[index + i] = buf32[index2 + i];
+ buf32[index2 + i] = value;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.merge = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = [];
+ var buf32 = [];
+ var buf8 = [];
+ for (var i = 0; i < 2; i++) {
+ imageData[i] = this.canvasCtx[i].getImageData(x, y, width, height);
+ buf32[i] = new Uint32Array(imageData[i].data.buffer);
+ buf8[i] = new Uint8ClampedArray(imageData[i].data.buffer);
+ }
+
+ var dst = this.current;
+ var src = (dst == 1) ? 0 : 1;
+ var size = width * height;
+ var index = 0;
+ for (var i = 0; i < size; i++) {
+ var r0 = buf8[0][index + 0];
+ var g0 = buf8[0][index + 1];
+ var b0 = buf8[0][index + 2];
+ var a0 = buf8[0][index + 3] / 255.0;
+ var r1 = buf8[1][index + 0];
+ var g1 = buf8[1][index + 1];
+ var b1 = buf8[1][index + 2];
+ var a1 = buf8[1][index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+ if (a > 0) {
+ var r = Math.floor((r1 * a1 + r0 * a0 * (1 - a1)) / a + 0.5);
+ var g = Math.floor((g1 * a1 + g0 * a0 * (1 - a1)) / a + 0.5);
+ var b = Math.floor((b1 * a1 + b0 * a0 * (1 - a1)) / a + 0.5);
+ }
+ buf8[src][index + 0] = 0;
+ buf8[src][index + 1] = 0;
+ buf8[src][index + 2] = 0;
+ buf8[src][index + 3] = 0;
+ buf8[dst][index + 0] = r;
+ buf8[dst][index + 1] = g;
+ buf8[dst][index + 2] = b;
+ buf8[dst][index + 3] = Math.floor(a * 255 + 0.5);
+ index += 4;
+ }
+
+ for (var i = 0; i < 2; i++) {
+ imageData[i].data.set(buf8[i]);
+ this.canvasCtx[i].putImageData(imageData[i], x, y);
+ }
+};
+
+Neo.Painter.prototype.blurRect = function(ctx, x, y, width, height) {
+ x = Math.round(x);
+ y = Math.round(y);
+ width = Math.round(width);
+ height = Math.round(height);
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var tmp = new Uint8ClampedArray(buf8.length);
+ for (var i = 0; i < buf8.length; i++) tmp[i] = buf8[i];
+
+ var index = 0;
+ var a1 = this.alpha / 12;
+ var blur = a1;
+
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ var rgba = [0, 0, 0, 0, 0];
+
+ this.addBlur(tmp, index, 1.0 - blur*4, rgba);
+
+ if (i > 0) this.addBlur(tmp, index - 4, blur, rgba);
+ if (i < width - 1) this.addBlur(tmp, index + 4, blur, rgba);
+ if (j > 0) this.addBlur(tmp, index - width*4, blur, rgba);
+ if (j < height - 1) this.addBlur(tmp, index + width*4, blur, rgba);
+
+ var w = rgba[4];
+ buf8[index + 0] = Math.round(rgba[0]);
+ buf8[index + 1] = Math.round(rgba[1]);
+ buf8[index + 2] = Math.round(rgba[2]);
+ buf8[index + 3] = Math.ceil((rgba[3] / w) * 255.0);
+
+ index += 4;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.addBlur = function(buffer, index, a, rgba) {
+ var r0 = rgba[0];
+ var g0 = rgba[1];
+ var b0 = rgba[2];
+ var a0 = rgba[3];
+ var r1 = buffer[index + 0];
+ var g1 = buffer[index + 1];
+ var b1 = buffer[index + 2];
+ var a1 = (buffer[index + 3] / 255.0) * a;
+ rgba[4] += a;
+
+ var a = a0 + a1;
+ if (a > 0) {
+ rgba[0] = (r1 * a1 + r0 * a0) / (a0 + a1);
+ rgba[1] = (g1 * a1 + g0 * a0) / (a0 + a1);
+ rgba[2] = (b1 * a1 + b0 * a0) / (a0 + a1);
+ rgba[3] = a;
+ }
+};
+
+Neo.Painter.prototype.pickColor = function(x, y) {
+ var r = 0xff, g = 0xff, b = 0xff, a;
+
+ x = Math.floor(x);
+ y = Math.floor(y);
+ if (x >= 0 && x < this.canvasWidth &&
+ y >= 0 && y < this.canvasHeight) {
+
+ for (var i = 0; i < 2; i++) {
+ if (this.visible[i]) {
+ var ctx = this.canvasCtx[i];
+ var imageData = ctx.getImageData(x, y, 1, 1);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var a = buf8[3] / 255.0;
+ r = r * (1.0 - a) + buf8[2] * a;
+ g = g * (1.0 - a) + buf8[1] * a;
+ b = b * (1.0 - a) + buf8[0] * a;
+ }
+ }
+ r = Math.max(Math.min(Math.round(r), 255), 0);
+ g = Math.max(Math.min(Math.round(g), 255), 0);
+ b = Math.max(Math.min(Math.round(b), 255), 0);
+ var result = r | g<<8 | b<<16;
+ }
+ this.setColor(result);
+
+
+ if (this.current > 0) {
+ if (a == 0 && (result == 0xffffff || this.getEmulationMode() < 2.16)) {
+ this.setToolByType(Neo.eraserTip.tools[Neo.eraserTip.mode]);
+
+ } else {
+ if (Neo.eraserTip.selected) {
+ this.setToolByType(Neo.penTip.tools[Neo.penTip.mode]);
+ }
+ }
+ }
+};
+
+Neo.Painter.prototype.fillHorizontalLine = function(buf32, x0, x1, y) {
+ var index = y * this.canvasWidth + x0;
+ var fillColor = this.getColor();
+ for (var x = x0; x <= x1; x++) {
+ buf32[index++] = fillColor;
+ }
+};
+
+Neo.Painter.prototype.scanLine = function(x0, x1, y, baseColor, buf32, stack) {
+ var width = this.canvasWidth;
+ for (var x = x0; x <= x1; x++) {
+ stack.push({x:x, y: y})
+ }
+/*
+ while (x0 <= x1) {
+ for (; x0 <= x1; x0++) {
+ if (buf32[y * width + x0] == baseColor) break;
+ }
+ if (x1 < x0) break;
+
+ for (; x0 <= x1; x0++) {
+ if (buf32[y * width + x0] != baseColor) break;
+ }
+ stack.push({x:x0 - 1, y: y})
+ }
+*/
+};
+
+Neo.Painter.prototype.fill = function(x, y, ctx) {
+ x = Math.round(x);
+ y = Math.round(y);
+
+ if (x < 0 || x >= this.canvasWidth || y < 0 || y >= this.canvasHeight) {
+ return;
+ }
+
+ var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var width = imageData.width;
+ var stack = [{x: x, y: y}];
+
+ var baseColor = buf32[y * width + x];
+ var fillColor = this.getColor();
+
+ if ((baseColor & 0xff000000) == 0 || (baseColor != fillColor)) {
+ while (stack.length > 0) {
+ if (stack.length > 1000000) {
+ console.log('too much stack')
+ break;
+ }
+ var point = stack.pop();
+ var x = point.x;
+ var y = point.y;
+ var x0 = x;
+ var x1 = x;
+ if (buf32[y * width + x] == fillColor) continue;
+ if (buf32[y * width + x] != baseColor) continue;
+
+ for (; 0 < x0; x0--) {
+ if (buf32[y * width + (x0 - 1)] != baseColor) break;
+ }
+ for (; x1 < this.canvasWidth - 1; x1++) {
+ if (buf32[y * width + (x1 + 1)] != baseColor) break;
+ }
+ this.fillHorizontalLine(buf32, x0, x1, y);
+
+ if (y + 1 < this.canvasHeight) {
+ this.scanLine(x0, x1, y + 1, baseColor, buf32, stack);
+ }
+ if (y - 1 >= 0) {
+ this.scanLine(x0, x1, y - 1, baseColor, buf32, stack);
+ }
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+ this.updateDestCanvas(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype.copy = function(x, y, width, height) {
+ this.tempX = 0;
+ this.tempY = 0;
+ this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+
+ var imageData = this.canvasCtx[this.current].getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ this.temp = new Uint32Array(buf32.length);
+ for (var i = 0; i < buf32.length; i++) {
+ this.temp[i] = buf32[i];
+ }
+
+ //tempCanvasに乗せる画像を作る
+ imageData = this.tempCanvasCtx.getImageData(x, y, width, height);
+ buf32 = new Uint32Array(imageData.data.buffer);
+ buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ for (var i = 0; i < buf32.length; i++) {
+ if (this.temp[i] >> 24) {
+ buf32[i] = this.temp[i] | 0xff000000;
+ } else {
+ buf32[i] = 0xffffffff;
+ }
+ }
+ imageData.data.set(buf8);
+ this.tempCanvasCtx.putImageData(imageData, x, y);
+};
+
+
+Neo.Painter.prototype.paste = function(x, y, width, height) {
+ var ctx = this.canvasCtx[this.current];
+// console.log(this.tempX, this.tempY);
+
+ var imageData = ctx.getImageData(x + this.tempX, y + this.tempY, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ for (var i = 0; i < buf32.length; i++) {
+ buf32[i] = this.temp[i];
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x + this.tempX, y + this.tempY);
+
+ this.temp = null;
+ this.tempX = 0;
+ this.tempY = 0;
+ this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype.turn = function(x, y, width, height) {
+ var ctx = this.canvasCtx[this.current];
+
+ // 傾けツールのバグを再現するため一番上のラインで対象領域を埋める
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var temp = new Uint32Array(buf32.length);
+
+ var index = 0;
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ temp[index] = buf32[index];
+ if (index >= width) {
+ buf32[index] = buf32[index % width];
+ }
+ index++;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+
+ // 90度回転させて貼り付け
+ imageData = ctx.getImageData(x, y, height, width);
+ buf32 = new Uint32Array(imageData.data.buffer);
+ buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ index = 0;
+ for (var j = height - 1; j >= 0; j--) {
+ for (var i = 0; i < width; i++) {
+ buf32[i * height + j] = temp[index++];
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.doFill = function(ctx, x, y, width, height, maskFunc) {
+ if (Math.round(x) != x) console.log("*");
+ if (Math.round(width) != width) console.log("*");
+ if (Math.round(height) != height) console.log("*");
+
+ var imageData = ctx.getImageData(x, y, width, height);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ var index = 0;
+
+ var r1 = this._currentColor[0];
+ var g1 = this._currentColor[1];
+ var b1 = this._currentColor[2];
+ var a1 = this.getAlpha(Neo.ALPHATYPE_FILL);
+
+ for (var j = 0; j < height; j++) {
+ for (var i = 0; i < width; i++) {
+ if (maskFunc && maskFunc.call(this, i, j, width, height)) {
+ //なぜか加算逆加算は適用されない
+ if (this.maskType >= Neo.Painter.MASKTYPE_ADD ||
+ !this.isMasked(buf8, index)) {
+ var r0 = buf8[index + 0];
+ var g0 = buf8[index + 1];
+ var b0 = buf8[index + 2];
+ var a0 = buf8[index + 3] / 255.0;
+
+ var a = a0 + a1 - a0 * a1;
+
+ if (a > 0) {
+ var a1x = a1;
+ var ax = 1 + a0 * (1 - a1x);
+
+ var r = (r1 + r0 * a0 * (1 - a1x)) / ax;
+ var g = (g1 + g0 * a0 * (1 - a1x)) / ax;
+ var b = (b1 + b0 * a0 * (1 - a1x)) / ax
+
+ r = (r1 > r0) ? Math.ceil(r) : Math.floor(r);
+ g = (g1 > g0) ? Math.ceil(g) : Math.floor(g);
+ b = (b1 > b0) ? Math.ceil(b) : Math.floor(b);
+ }
+
+ var tmp = a * 255;
+ a = Math.ceil(tmp);
+
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+ }
+ }
+ index += 4;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, x, y);
+};
+
+Neo.Painter.prototype.rectFillMask = function(x, y, width, height) {
+ return true;
+};
+
+Neo.Painter.prototype.rectMask = function(x, y, width, height) {
+ var d = this.lineWidth;
+ return (x < d || x > width - 1 - d ||
+ y < d || y > height - 1 - d) ? true : false;
+};
+
+Neo.Painter.prototype.ellipseFillMask = function(x, y, width, height) {
+ var cx = (width - 1) / 2.0;
+ var cy = (height - 1) / 2.0;
+ x = (x - cx) / (cx + 1);
+ y = (y - cy) / (cy + 1);
+
+ return ((x * x) + (y * y) < 1) ? true : false;
+}
+
+Neo.Painter.prototype.ellipseMask = function(x, y, width, height) {
+ var d = this.lineWidth;
+ var cx = (width - 1) / 2.0;
+ var cy = (height - 1) / 2.0;
+
+ if (cx <= d || cy <= d) return this.ellipseFillMask(x, y, width, height);
+
+ var x2 = (x - cx) / (cx - d + 1);
+ var y2 = (y - cy) / (cy - d + 1);
+
+ x = (x - cx) / (cx + 1);
+ y = (y - cy) / (cy + 1);
+
+ if ((x * x) + (y * y) < 1) {
+ if ((x2 * x2) + (y2 * y2) >= 1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*
+-----------------------------------------------------------------------
+*/
+
+Neo.Painter.prototype.getDestCanvasPosition = function(mx, my, isClip, isCenter) {
+ var mx = Math.floor(mx); //Math.round(mx);
+ var my = Math.floor(my); //Math.round(my);
+ if (isCenter) {
+ mx += 0.499;
+ my += 0.499;
+ }
+ var x = (mx - this.zoomX + this.destCanvas.width * 0.5 / this.zoom) * this.zoom;
+ var y = (my - this.zoomY + this.destCanvas.height * 0.5 / this.zoom) * this.zoom;
+
+ if (isClip) {
+ x = Math.max(Math.min(x, this.destCanvas.width), 0);
+ y = Math.max(Math.min(y, this.destCanvas.height), 0);
+ }
+ return {x:x, y:y};
+};
+
+Neo.Painter.prototype.isWidget = function(element) {
+ while (1) {
+ if (element == null ||
+ element.id == "canvas" ||
+ element.id == "container") break;
+
+ if (element.id == "tools" ||
+ element.className == "buttonOn" ||
+ element.className == "buttonOff" ||
+ element.className == "inputText") {
+ return true;
+ }
+ element = element.parentNode;
+ }
+ return false;
+};
+
+Neo.Painter.prototype.isContainer = function(element) {
+ while (1) {
+ if (element == null) break;
+ if (element.id == "container") return true;
+ element = element.parentNode;
+ }
+ return false;
+};
+
+Neo.Painter.prototype.cancelTool = function(e) {
+ if (this.tool) {
+ this.isMouseDown = false;
+ this.tool.upHandler(this);
+
+// switch (this.tool.type) {
+// case Neo.Painter.TOOLTYPE_HAND:
+// case Neo.Painter.TOOLTYPE_SLIDER:
+// this.isMouseDown = false;
+// this.tool.upHandler(this);
+// }
+ }
+};
+
+Neo.Painter.prototype.loadImage = function (filename) {
+ console.log("loadImage " + filename);
+ var img = new Image();
+ img.src = filename;
+ img.onload = function() {
+ var oe = Neo.painter;
+ oe.canvasCtx[0].drawImage(img, 0, 0);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight);
+ };
+};
+
+Neo.Painter.prototype.loadSession = function (filename) {
+ if (Neo.storage) {
+ var img0 = new Image();
+ img0.src = Neo.storage.getItem('layer0');
+ img0.onload = function() {
+ var img1 = new Image();
+ img1.src = Neo.storage.getItem('layer1');
+ img1.onload = function() {
+ var oe = Neo.painter;
+ oe.canvasCtx[0].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.canvasCtx[1].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.canvasCtx[0].drawImage(img0, 0, 0);
+ oe.canvasCtx[1].drawImage(img1, 0, 0);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight);
+ }
+ }
+ }
+};
+
+Neo.Painter.prototype.saveSession = function() {
+ if (Neo.storage) {
+ Neo.storage.setItem('timestamp', +(new Date()));
+ Neo.storage.setItem('layer0', this.canvas[0].toDataURL('image/png'));
+ Neo.storage.setItem('layer1', this.canvas[1].toDataURL('image/png'));
+ }
+};
+
+Neo.Painter.prototype.clearSession = function() {
+ if (Neo.storage) {
+ Neo.storage.removeItem('timestamp');
+ Neo.storage.removeItem('layer0');
+ Neo.storage.removeItem('layer1');
+ }
+};
+
+Neo.Painter.prototype.sortColor = function(r0, g0, b0) {
+ var min = (r0 < g0) ? ((r0 < b0) ? 0 : 2) : ((g0 < b0) ? 1 : 2);
+ var max = (r0 > g0) ? ((r0 > b0) ? 0 : 2) : ((g0 > b0) ? 1 : 2);
+ var mid = (min + max == 1) ? 2 : ((min + max == 2) ? 1 : 0);
+ return [min, mid, max];
+};
+
+Neo.Painter.prototype.doText = function(x, y, string, fontSize) {
+ //テキスト描画
+ //描画位置がずれるので適当に調整
+ var offset = parseInt(fontSize, 10);
+// y -= Math.round((5.0 + offset/8) / this.zoom);
+// x += Math.round(2.0 / this.zoom);
+
+ var ctx = this.tempCanvasCtx;
+ ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+ ctx.save();
+ ctx.translate(x, y);
+// ctx.scale(1/this.zoom, 1/this.zoom);
+
+ var fontFamily = Neo.painter.inputText.style.fontFamily || "Arial";
+ ctx.font = fontSize + " " + fontFamily;
+
+ ctx.fillStyle = 0;
+ ctx.fillText(string, 0, 0);
+ ctx.restore();
+
+ // 適当に二値化
+ var c = this.getColor();
+ var r = c & 0xff;
+ var g = (c & 0xff00) >> 8;
+ var b = (c & 0xff0000) >> 16;
+ var a = Math.round(this.alpha * 255.0);
+
+ var imageData = ctx.getImageData(0, 0, this.canvasWidth, this.canvasHeight);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var length = this.canvasWidth * this.canvasHeight;
+ var index = 0;
+ for (var i = 0; i < length; i++) {
+ if (buf8[index + 3] >= 0x60) {
+ buf8[index + 0] = r;
+ buf8[index + 1] = g;
+ buf8[index + 2] = b;
+ buf8[index + 3] = a;
+
+ } else {
+ buf8[index + 0] = 0;
+ buf8[index + 1] = 0;
+ buf8[index + 2] = 0;
+ buf8[index + 3] = 0;
+ }
+ index += 4;
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+
+ //キャンバスに貼り付け
+ ctx = this.canvasCtx[this.current];
+ ctx.globalAlpha = 1.0;
+ ctx.drawImage(this.tempCanvas,
+ 0, 0, this.canvasWidth, this.canvasHeight,
+ 0, 0, this.canvasWidth, this.canvasHeight);
+
+ this.tempCanvasCtx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
+};
+
+Neo.Painter.prototype.isUIPaused = function() {
+ if (this.drawType == Neo.Painter.DRAWTYPE_BEZIER) {
+ if (this.tool.step && this.tool.step > 0) {
+ return true;
+ }
+ }
+ return false;
+};
+
+Neo.Painter.prototype.getEmulationMode = function() {
+ return parseFloat(Neo.config.neo_emulation_mode || 2.22)
+};
+
+'use strict';
+
+Neo.ToolBase = function() {};
+
+Neo.ToolBase.prototype.startX;
+Neo.ToolBase.prototype.startY;
+Neo.ToolBase.prototype.init = function(oe) {}
+Neo.ToolBase.prototype.kill = function(oe) {}
+Neo.ToolBase.prototype.lineType = Neo.Painter.LINETYPE_NONE;
+
+Neo.ToolBase.prototype.downHandler = function(oe) {
+ this.startX = oe.mouseX;
+ this.startY = oe.mouseY;
+};
+
+Neo.ToolBase.prototype.upHandler = function(oe) {
+};
+
+Neo.ToolBase.prototype.moveHandler = function(oe) {
+};
+
+Neo.ToolBase.prototype.transformForZoom = function(oe) {
+ var ctx = oe.destCanvasCtx;
+ ctx.translate(oe.canvasWidth * 0.5, oe.canvasHeight * 0.5);
+ ctx.scale(oe.zoom, oe.zoom);
+ ctx.translate(-oe.zoomX, -oe.zoomY);
+};
+
+Neo.ToolBase.prototype.getType = function() {
+ return this.type;
+};
+
+Neo.ToolBase.prototype.getToolButton = function() {
+ switch (this.type) {
+ case Neo.Painter.TOOLTYPE_PEN:
+ case Neo.Painter.TOOLTYPE_BRUSH:
+ case Neo.Painter.TOOLTYPE_TEXT:
+ return Neo.penTip;
+
+ case Neo.Painter.TOOLTYPE_TONE:
+ case Neo.Painter.TOOLTYPE_BLUR:
+ case Neo.Painter.TOOLTYPE_DODGE:
+ case Neo.Painter.TOOLTYPE_BURN:
+ return Neo.pen2Tip;
+
+ case Neo.Painter.TOOLTYPE_RECT:
+ case Neo.Painter.TOOLTYPE_RECTFILL:
+ case Neo.Painter.TOOLTYPE_ELLIPSE:
+ case Neo.Painter.TOOLTYPE_ELLIPSEFILL:
+ return Neo.effectTip;
+
+ case Neo.Painter.TOOLTYPE_COPY:
+ case Neo.Painter.TOOLTYPE_MERGE:
+ case Neo.Painter.TOOLTYPE_BLURRECT:
+ case Neo.Painter.TOOLTYPE_FLIP_H:
+ case Neo.Painter.TOOLTYPE_FLIP_V:
+ case Neo.Painter.TOOLTYPE_TURN:
+ return Neo.effect2Tip;
+
+ case Neo.Painter.TOOLTYPE_ERASER:
+ case Neo.Painter.TOOLTYPE_ERASEALL:
+ case Neo.Painter.TOOLTYPE_ERASERECT:
+ return Neo.eraserTip;
+
+ case Neo.Painter.TOOLTYPE_FILL:
+ return Neo.fillButton;
+ }
+ return null;
+};
+
+Neo.ToolBase.prototype.getReserve = function() {
+ switch (this.type) {
+ case Neo.Painter.TOOLTYPE_ERASER:
+ return Neo.reserveEraser;
+
+ case Neo.Painter.TOOLTYPE_PEN:
+ case Neo.Painter.TOOLTYPE_BRUSH:
+ case Neo.Painter.TOOLTYPE_TONE:
+ case Neo.Painter.TOOLTYPE_ERASERECT:
+ case Neo.Painter.TOOLTYPE_ERASEALL:
+ case Neo.Painter.TOOLTYPE_COPY:
+ case Neo.Painter.TOOLTYPE_MERGE:
+ case Neo.Painter.TOOLTYPE_FIP_H:
+ case Neo.Painter.TOOLTYPE_FIP_V:
+
+ case Neo.Painter.TOOLTYPE_DODGE:
+ case Neo.Painter.TOOLTYPE_BURN:
+ case Neo.Painter.TOOLTYPE_BLUR:
+ case Neo.Painter.TOOLTYPE_BLURRECT:
+
+ case Neo.Painter.TOOLTYPE_TEXT:
+ case Neo.Painter.TOOLTYPE_TURN:
+ case Neo.Painter.TOOLTYPE_RECT:
+ case Neo.Painter.TOOLTYPE_RECTFILL:
+ case Neo.Painter.TOOLTYPE_ELLIPSE:
+ case Neo.Painter.TOOLTYPE_ELLIPSEFILL:
+ return Neo.reservePen;
+
+ }
+ return null;
+};
+
+Neo.ToolBase.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.updateUI();
+ }
+};
+
+Neo.ToolBase.prototype.saveStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ reserve.size = Neo.painter.lineWidth;
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ DrawToolBase(描画ツールのベースクラス)
+ -------------------------------------------------------------------------
+*/
+
+Neo.DrawToolBase = function() {};
+Neo.DrawToolBase.prototype = new Neo.ToolBase();
+Neo.DrawToolBase.prototype.isUpMove = false;
+Neo.DrawToolBase.prototype.step = 0;
+
+Neo.DrawToolBase.prototype.init = function() {
+ this.step = 0;
+ this.isUpMove = true;
+};
+
+Neo.DrawToolBase.prototype.downHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandDownHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineDownHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierDownHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.upHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandUpHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineUpHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierUpHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.moveHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierMoveHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.upMoveHandler = function(oe) {
+ switch (oe.drawType) {
+ case Neo.Painter.DRAWTYPE_FREEHAND:
+ this.freeHandUpMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_LINE:
+ this.lineUpMoveHandler(oe); break;
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierUpMoveHandler(oe); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.keyDownHandler = function(e) {
+ switch (Neo.painter.drawType) {
+ case Neo.Painter.DRAWTYPE_BEZIER:
+ this.bezierKeyDownHandler(e); break;
+ }
+};
+
+Neo.DrawToolBase.prototype.rollOverHandler= function(oe) {};
+Neo.DrawToolBase.prototype.rollOutHandler= function(oe) {
+ if (!oe.isMouseDown && !oe.isMouseDownRight){
+ oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+Neo.DrawToolBase.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 1.0;
+ Neo.updateUI();
+ };
+};
+
+
+/* FreeHand (手書き) */
+
+Neo.DrawToolBase.prototype.freeHandDownHandler = function(oe) {
+ //Register undo first;
+ oe._pushUndo();
+
+ oe.prepareDrawing();
+ this.isUpMove = false;
+ var ctx = oe.canvasCtx[oe.current];
+ if (oe.alpha >= 1 || this.lineType != Neo.Painter.LINETYPE_BRUSH) {
+ var x0 = Math.floor(oe.mouseX);
+ var y0 = Math.floor(oe.mouseY);
+ oe.drawLine(ctx, x0, y0, x0, y0, this.lineType);
+ }
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+
+ if (oe.alpha >= 1) {
+ var r = Math.ceil(oe.lineWidth / 2);
+ var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.mouseX, oe.mouseY, r);
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ }
+};
+
+Neo.DrawToolBase.prototype.freeHandUpHandler = function(oe) {
+ oe.tempCanvasCtx.clearRect(0,0,oe.canvasWidth, oe.canvasHeight);
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+
+ // oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ // this.drawCursor(oe);
+ oe.prevLine = null;
+};
+
+Neo.DrawToolBase.prototype.freeHandMoveHandler = function(oe) {
+ var ctx = oe.canvasCtx[oe.current];
+ var x0 = Math.floor(oe.mouseX);
+ var y0 = Math.floor(oe.mouseY);
+ var x1 = Math.floor(oe.prevMouseX);
+ var y1 = Math.floor(oe.prevMouseY);
+ oe.drawLine(ctx, x0, y0, x1, y1, this.lineType);
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+
+ var r = Math.ceil(oe.lineWidth / 2);
+ var rect = oe.getBound(oe.mouseX, oe.mouseY, oe.prevMouseX, oe.prevMouseY, r);
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+};
+
+Neo.DrawToolBase.prototype.freeHandUpMoveHandler = function(oe) {
+ this.isUpMove = true;
+
+ if (oe.cursorRect) {
+ var rect = oe.cursorRect;
+ oe.updateDestCanvas(rect[0], rect[1], rect[2], rect[3], true);
+ oe.cursorRect = null;
+ }
+ this.drawCursor(oe);
+};
+
+Neo.DrawToolBase.prototype.drawCursor = function(oe) {
+ if (oe.lineWidth <= 8) return;
+ var mx = oe.mouseX;
+ var my = oe.mouseY;
+ var d = oe.lineWidth;
+
+ var x = (mx - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom;
+ var y = (my - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom;
+ var r = d * 0.5 * oe.zoom;
+
+ if (!(x > -r &&
+ y > -r &&
+ x < oe.destCanvas.width + r &&
+ y < oe.destCanvas.height + r)) return;
+
+ var ctx = oe.destCanvasCtx;
+ ctx.save();
+ this.transformForZoom(oe)
+
+ var c = (this.type == Neo.Painter.TOOLTYPE_ERASER) ? 0x0000ff : 0xffff7f;
+ oe.drawXOREllipse(ctx, x-r, y-r, r*2, r*2, false, c);
+
+ ctx.restore();
+ oe.cursorRect = oe.getBound(mx, my, mx, my, Math.ceil(d / 2));
+}
+
+
+/* Line (直線) */
+
+Neo.DrawToolBase.prototype.lineDownHandler = function(oe) {
+ this.isUpMove = false;
+ this.startX = Math.floor(oe.mouseX);
+ this.startY = Math.floor(oe.mouseY);
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+};
+
+Neo.DrawToolBase.prototype.lineUpHandler = function(oe) {
+ if (this.isUpMove == false) {
+ this.isUpMove = true;
+
+ oe._pushUndo();
+ oe.prepareDrawing();
+ var ctx = oe.canvasCtx[oe.current];
+ var x0 = Math.floor(oe.mouseX);
+ var y0 = Math.floor(oe.mouseY);
+ oe.drawLine(ctx, x0, y0, this.startX, this.startY, this.lineType);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+Neo.DrawToolBase.prototype.lineMoveHandler = function(oe) {
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ this.drawLineCursor(oe);
+};
+
+Neo.DrawToolBase.prototype.lineUpMoveHandler = function(oe) {
+};
+
+Neo.DrawToolBase.prototype.drawLineCursor = function(oe, mx, my) {
+ if (!mx) mx = Math.floor(oe.mouseX);
+ if (!my) my = Math.floor(oe.mouseY);
+ var nx = this.startX;
+ var ny = this.startY;
+ var ctx = oe.destCanvasCtx;
+ ctx.save();
+ this.transformForZoom(oe)
+
+ var x0 = (mx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom;
+ var y0 = (my +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom;
+ var x1 = (nx +.499 - oe.zoomX + oe.destCanvas.width * 0.5 / oe.zoom) * oe.zoom;
+ var y1 = (ny +.499 - oe.zoomY + oe.destCanvas.height * 0.5 / oe.zoom) * oe.zoom;
+ oe.drawXORLine(ctx, x0, y0, x1, y1);
+
+ ctx.restore();
+};
+
+
+/* Bezier (BZ曲線) */
+
+Neo.DrawToolBase.prototype.bezierDownHandler = function(oe) {
+ this.isUpMove = false;
+
+ if (this.step == 0) {
+ this.startX = this.x0 = Math.floor(oe.mouseX);
+ this.startY = this.y0 = Math.floor(oe.mouseY);
+ }
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+};
+
+Neo.DrawToolBase.prototype.bezierUpHandler = function(oe) {
+ if (this.isUpMove == false) {
+ this.isUpMove = true;
+ }
+
+ this.step++;
+ switch (this.step) {
+ case 1:
+ oe.prepareDrawing();
+ this.x3 = Math.floor(oe.mouseX);
+ this.y3 = Math.floor(oe.mouseY);
+ break;
+
+ case 2:
+ this.x1 = Math.floor(oe.mouseX);
+ this.y1 = Math.floor(oe.mouseY);
+ break;
+
+ case 3:
+ this.x2 = Math.floor(oe.mouseX);
+ this.y2 = Math.floor(oe.mouseY);
+
+ oe._pushUndo();
+ oe.drawBezier(oe.canvasCtx[oe.current],
+ this.x0, this.y0, this.x1, this.y1,
+ this.x2, this.y2, this.x3, this.y3, this.lineType);
+
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ this.step = 0;
+ break;
+
+ default:
+ this.step = 0;
+ break;
+ }
+};
+
+Neo.DrawToolBase.prototype.bezierMoveHandler = function(oe) {
+ switch (this.step) {
+ case 0:
+ if (!this.isUpMove) {
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false);
+ this.drawLineCursor(oe);
+ }
+ break;
+ case 1:
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false);
+ this.drawBezierCursor1(oe);
+ break;
+
+ case 2:
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, false);
+ this.drawBezierCursor2(oe);
+ break;
+ }
+};
+
+Neo.DrawToolBase.prototype.bezierUpMoveHandler = function(oe) {
+ this.bezierMoveHandler(oe);
+};
+
+Neo.DrawToolBase.prototype.bezierKeyDownHandler = function(e) {
+ if (e.keyCode == 27) { //Escでキャンセル
+ this.step = 0;
+
+ var oe = Neo.painter;
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+
+Neo.DrawToolBase.prototype.drawBezierCursor1 = function(oe) {
+ var ctx = oe.destCanvasCtx;
+ // var x = oe.mouseX; //Math.floor(oe.mouseX);
+ // var y = oe.mouseY; //Math.floor(oe.mouseY);
+ var stab = oe.getStabilized();
+ var x = Math.floor(stab[0]);
+ var y = Math.floor(stab[1]);
+ var p = oe.getDestCanvasPosition(x, y, false, true);
+ var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true);
+ var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true);
+
+ // handle
+ oe.drawXORLine(ctx, p0.x, p0.y, p.x, p.y);
+ oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8);
+ oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8);
+
+ // preview
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.drawBezier(oe.tempCanvasCtx,
+ this.x0, this.y0,
+ x, y,
+ x, y,
+ this.x3, this.y3, this.lineType);
+
+ ctx.save();
+ ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5);
+ ctx.scale(oe.zoom, oe.zoom);
+ ctx.translate(-oe.zoomX, -oe.zoomY);
+ ctx.drawImage(oe.tempCanvas,
+ 0, 0, oe.canvasWidth, oe.canvasHeight,
+ 0, 0, oe.canvasWidth, oe.canvasHeight);
+
+ ctx.restore();
+};
+
+Neo.DrawToolBase.prototype.drawBezierCursor2 = function(oe) {
+ var ctx = oe.destCanvasCtx;
+ // var x = oe.mouseX; //Math.floor(oe.mouseX);
+ // var y = oe.mouseY; //Math.floor(oe.mouseY);
+ var stab = oe.getStabilized();
+ var x = Math.floor(stab[0]);
+ var y = Math.floor(stab[1]);
+ var p = oe.getDestCanvasPosition(oe.mouseX, oe.mouseY, false, true);
+ var p0 = oe.getDestCanvasPosition(this.x0, this.y0, false, true);
+ var p1 = oe.getDestCanvasPosition(this.x1, this.y1, false, true);
+ var p3 = oe.getDestCanvasPosition(this.x3, this.y3, false, true);
+
+ // handle
+ oe.drawXORLine(ctx, p3.x, p3.y, p.x, p.y);
+ oe.drawXOREllipse(ctx, p.x - 4, p.y - 4, 8, 8);
+ oe.drawXORLine(ctx, p0.x, p0.y, p1.x, p1.y);
+ oe.drawXOREllipse(ctx, p1.x - 4, p1.y - 4, 8, 8);
+ oe.drawXOREllipse(ctx, p0.x - 4, p0.y - 4, 8, 8);
+
+ // preview
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.drawBezier(oe.tempCanvasCtx,
+ this.x0, this.y0,
+ this.x1, this.y1,
+ x, y,
+ this.x3, this.y3, this.lineType);
+
+ ctx.save();
+ ctx.translate(oe.destCanvas.width*.5, oe.destCanvas.height*.5);
+ ctx.scale(oe.zoom, oe.zoom);
+ ctx.translate(-oe.zoomX, -oe.zoomY);
+ ctx.drawImage(oe.tempCanvas,
+ 0, 0, oe.canvasWidth, oe.canvasHeight,
+ 0, 0, oe.canvasWidth, oe.canvasHeight);
+ ctx.restore();
+};
+
+/*
+ -------------------------------------------------------------------------
+ Pen(鉛筆)
+ -------------------------------------------------------------------------
+*/
+
+Neo.PenTool = function() {};
+Neo.PenTool.prototype = new Neo.DrawToolBase();
+Neo.PenTool.prototype.type = Neo.Painter.TOOLTYPE_PEN;
+Neo.PenTool.prototype.lineType = Neo.Painter.LINETYPE_PEN;
+
+Neo.PenTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 1.0;
+ Neo.updateUI();
+ };
+}
+
+/*
+ -------------------------------------------------------------------------
+ Brush(水彩)
+ -------------------------------------------------------------------------
+*/
+
+Neo.BrushTool = function() {};
+Neo.BrushTool.prototype = new Neo.DrawToolBase();
+Neo.BrushTool.prototype.type = Neo.Painter.TOOLTYPE_BRUSH;
+Neo.BrushTool.prototype.lineType = Neo.Painter.LINETYPE_BRUSH;
+
+Neo.BrushTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = this.getAlpha();
+ Neo.updateUI();
+ }
+};
+
+Neo.BrushTool.prototype.getAlpha = function() {
+ var alpha = 241 - Math.floor(Neo.painter.lineWidth / 2) * 6;
+ return alpha / 255.0;
+};
+
+/*
+ -------------------------------------------------------------------------
+ Tone(トーン)
+ -------------------------------------------------------------------------
+*/
+
+Neo.ToneTool = function() {};
+Neo.ToneTool.prototype = new Neo.DrawToolBase();
+Neo.ToneTool.prototype.type = Neo.Painter.TOOLTYPE_TONE;
+Neo.ToneTool.prototype.lineType = Neo.Painter.LINETYPE_TONE;
+
+Neo.ToneTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 23 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ Eraser(消しペン)
+ -------------------------------------------------------------------------
+*/
+
+Neo.EraserTool = function() {};
+Neo.EraserTool.prototype = new Neo.DrawToolBase();
+Neo.EraserTool.prototype.type = Neo.Painter.TOOLTYPE_ERASER;
+Neo.EraserTool.prototype.lineType = Neo.Painter.LINETYPE_ERASER;
+
+
+/*
+ -------------------------------------------------------------------------
+ Blur(ぼかし)
+ -------------------------------------------------------------------------
+*/
+
+Neo.BlurTool = function() {};
+Neo.BlurTool.prototype = new Neo.DrawToolBase();
+Neo.BlurTool.prototype.type = Neo.Painter.TOOLTYPE_BLUR;
+Neo.BlurTool.prototype.lineType = Neo.Painter.LINETYPE_BLUR;
+
+Neo.BlurTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 128 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ Dodge(覆い焼き)
+ -------------------------------------------------------------------------
+*/
+
+Neo.DodgeTool = function() {};
+Neo.DodgeTool.prototype = new Neo.DrawToolBase();
+Neo.DodgeTool.prototype.type = Neo.Painter.TOOLTYPE_DODGE;
+Neo.DodgeTool.prototype.lineType = Neo.Painter.LINETYPE_DODGE;
+
+Neo.DodgeTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 128 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ Burn(焼き込み)
+ -------------------------------------------------------------------------
+*/
+
+Neo.BurnTool = function() {};
+Neo.BurnTool.prototype = new Neo.DrawToolBase();
+Neo.BurnTool.prototype.type = Neo.Painter.TOOLTYPE_BURN;
+Neo.BurnTool.prototype.lineType = Neo.Painter.LINETYPE_BURN;
+
+Neo.BurnTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 128 / 255.0;
+ Neo.updateUI();
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ Hand(スクロール)
+ -------------------------------------------------------------------------
+*/
+
+Neo.HandTool = function() {};
+Neo.HandTool.prototype = new Neo.ToolBase();
+Neo.HandTool.prototype.type = Neo.Painter.TOOLTYPE_HAND;
+Neo.HandTool.prototype.isUpMove = false;
+Neo.HandTool.prototype.reverse = false;
+
+Neo.HandTool.prototype.downHandler = function(oe) {
+ oe.tempCanvasCtx.clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+
+ this.isDrag = true;
+ this.startX = oe.rawMouseX;
+ this.startY = oe.rawMouseY;
+};
+
+Neo.HandTool.prototype.upHandler = function(oe) {
+ this.isDrag = false;
+ oe.popTool();
+};
+
+Neo.HandTool.prototype.moveHandler = function(oe) {
+ if (this.isDrag) {
+ var dx = this.startX - oe.rawMouseX;
+ var dy = this.startY - oe.rawMouseY;
+
+ var ax = oe.destCanvas.width / (oe.canvasWidth * oe.zoom);
+ var ay = oe.destCanvas.height / (oe.canvasHeight * oe.zoom);
+ var barWidth = oe.destCanvas.width * ax;
+ var barHeight = oe.destCanvas.height * ay;
+ var scrollWidthInScreen = oe.destCanvas.width - barWidth - 2;
+ var scrollHeightInScreen = oe.destCanvas.height - barHeight - 2;
+
+ dx *= oe.scrollWidth / scrollWidthInScreen;
+ dy *= oe.scrollHeight / scrollHeightInScreen;
+
+ if (this.reverse) {
+ dx *= -1;
+ dy *= -1;
+ }
+
+ oe.setZoomPosition(oe.zoomX - dx, oe.zoomY - dy);
+
+ this.startX = oe.rawMouseX;
+ this.startY = oe.rawMouseY;
+ }
+};
+
+Neo.HandTool.prototype.upMoveHandler = function(oe) {}
+Neo.HandTool.prototype.rollOverHandler= function(oe) {}
+Neo.HandTool.prototype.rollOutHandler= function(oe) {};
+
+/*
+ -------------------------------------------------------------------------
+ Slider(色やサイズのスライダを操作している時)
+ -------------------------------------------------------------------------
+*/
+
+Neo.SliderTool = function() {};
+Neo.SliderTool.prototype = new Neo.ToolBase();
+Neo.SliderTool.prototype.type = Neo.Painter.TOOLTYPE_SLIDER;
+Neo.SliderTool.prototype.isUpMove = false;
+Neo.SliderTool.prototype.alt = false;
+
+Neo.SliderTool.prototype.downHandler = function(oe) {
+ if (!oe.isShiftDown) this.isDrag = true;
+
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+
+ var rect = this.target.getBoundingClientRect();
+ var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider'];
+ Neo.sliders[sliderType].downHandler(oe.rawMouseX - rect.left,
+ oe.rawMouseY - rect.top);
+};
+
+Neo.SliderTool.prototype.upHandler = function(oe) {
+ this.isDrag = false;
+ oe.popTool();
+
+ var rect = this.target.getBoundingClientRect();
+ var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider'];
+ Neo.sliders[sliderType].upHandler(oe.rawMouseX - rect.left,
+ oe.rawMouseY - rect.top);
+};
+
+Neo.SliderTool.prototype.moveHandler = function(oe) {
+ if (this.isDrag) {
+ var rect = this.target.getBoundingClientRect();
+ var sliderType = (this.alt) ? Neo.SLIDERTYPE_SIZE : this.target['data-slider'];
+ Neo.sliders[sliderType].moveHandler(oe.rawMouseX - rect.left,
+ oe.rawMouseY - rect.top);
+ }
+};
+
+Neo.SliderTool.prototype.upMoveHandler = function(oe) {}
+Neo.SliderTool.prototype.rollOverHandler= function(oe) {}
+Neo.SliderTool.prototype.rollOutHandler= function(oe) {}
+
+/*
+ -------------------------------------------------------------------------
+ Fill(塗り潰し)
+ -------------------------------------------------------------------------
+*/
+
+Neo.FillTool = function() {};
+Neo.FillTool.prototype = new Neo.ToolBase();
+Neo.FillTool.prototype.type = Neo.Painter.TOOLTYPE_FILL;
+Neo.FillTool.prototype.isUpMove = false;
+
+Neo.FillTool.prototype.downHandler = function(oe) {
+ var x = Math.floor(oe.mouseX);
+ var y = Math.floor(oe.mouseY);
+ oe._pushUndo();
+ oe.fill(x, y, oe.canvasCtx[oe.current]);
+};
+
+Neo.FillTool.prototype.upHandler = function(oe) {
+};
+
+Neo.FillTool.prototype.moveHandler = function(oe) {
+};
+
+Neo.FillTool.prototype.rollOutHandler= function(oe) {};
+Neo.FillTool.prototype.upMoveHandler = function(oe) {}
+Neo.FillTool.prototype.rollOverHandler= function(oe) {}
+
+
+/*
+ -------------------------------------------------------------------------
+ EraseAll(全消し)
+ -------------------------------------------------------------------------
+*/
+
+Neo.EraseAllTool = function() {};
+Neo.EraseAllTool.prototype = new Neo.ToolBase();
+Neo.EraseAllTool.prototype.type = Neo.Painter.TOOLTYPE_ERASEALL;
+Neo.EraseAllTool.prototype.isUpMove = false;
+
+Neo.EraseAllTool.prototype.downHandler = function(oe) {
+ oe._pushUndo();
+
+ oe.prepareDrawing();
+ oe.canvasCtx[oe.current].clearRect(0, 0, oe.canvasWidth, oe.canvasHeight);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+Neo.EraseAllTool.prototype.upHandler = function(oe) {
+};
+
+Neo.EraseAllTool.prototype.moveHandler = function(oe) {
+};
+
+Neo.EraseAllTool.prototype.rollOutHandler= function(oe) {};
+Neo.EraseAllTool.prototype.upMoveHandler = function(oe) {};
+Neo.EraseAllTool.prototype.rollOverHandler= function(oe) {};
+
+
+/*
+ -------------------------------------------------------------------------
+ EffectToolBase(エフェックトツールのベースクラス)
+ -------------------------------------------------------------------------
+*/
+
+Neo.EffectToolBase = function() {};
+Neo.EffectToolBase.prototype = new Neo.ToolBase();
+Neo.EffectToolBase.prototype.isUpMove = false;
+
+Neo.EffectToolBase.prototype.downHandler = function(oe) {
+ this.isUpMove = false;
+
+ this.startX = this.endX = oe.clipMouseX;
+ this.startY = this.endY = oe.clipMouseY;
+};
+
+Neo.EffectToolBase.prototype.upHandler = function(oe) {
+ if (this.isUpMove) return;
+ this.isUpMove = true;
+
+ this.startX = Math.floor(this.startX);
+ this.startY = Math.floor(this.startY);
+ this.endX = Math.floor(this.endX);
+ this.endY = Math.floor(this.endY);
+
+ var x = (this.startX < this.endX) ? this.startX : this.endX;
+ var y = (this.startY < this.endY) ? this.startY : this.endY;
+ var width = Math.abs(this.startX - this.endX) + 1;
+ var height = Math.abs(this.startY - this.endY) + 1;
+ var ctx = oe.canvasCtx[oe.current];
+
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ if (x + width > oe.canvasWidth) width = oe.canvasWidth - x;
+ if (y + height > oe.canvasHeight) height = oe.canvasHeight - y;
+
+ if (width > 0 && height > 0) {
+ oe._pushUndo();
+ oe.prepareDrawing();
+ this.doEffect(oe, x, y, width, height);
+ }
+
+ if (oe.tool.type != Neo.Painter.TOOLTYPE_PASTE) {
+ oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+Neo.EffectToolBase.prototype.moveHandler = function(oe) {
+ this.endX = oe.clipMouseX;
+ this.endY = oe.clipMouseY;
+
+ oe.updateDestCanvas(0,0,oe.canvasWidth, oe.canvasHeight, true);
+ this.drawCursor(oe);
+};
+
+Neo.EffectToolBase.prototype.rollOutHandler= function(oe) {};
+Neo.EffectToolBase.prototype.upMoveHandler = function(oe) {};
+Neo.EffectToolBase.prototype.rollOverHandler= function(oe) {};
+
+Neo.EffectToolBase.prototype.drawCursor = function(oe) {
+ var ctx = oe.destCanvasCtx;
+
+ ctx.save();
+ this.transformForZoom(oe);
+
+ var start = oe.getDestCanvasPosition(this.startX, this.startY, true);
+ var end = oe.getDestCanvasPosition(this.endX, this.endY, true);
+
+ var x = (start.x < end.x) ? start.x : end.x;
+ var y = (start.y < end.y) ? start.y : end.y;
+ var width = Math.abs(start.x - end.x) + oe.zoom;
+ var height = Math.abs(start.y - end.y) + oe.zoom;
+
+ if (this.isEllipse) {
+ oe.drawXOREllipse(ctx, x, y, width, height, this.isFill);
+
+ } else {
+ oe.drawXORRect(ctx, x, y, width, height, this.isFill);
+ }
+ ctx.restore();
+};
+
+Neo.EffectToolBase.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = this.defaultAlpha || 1.0;
+ Neo.updateUI();
+ };
+};
+
+/*
+ -------------------------------------------------------------------------
+ EraseRect(消し四角)
+ -------------------------------------------------------------------------
+*/
+
+Neo.EraseRectTool = function() {};
+Neo.EraseRectTool.prototype = new Neo.EffectToolBase();
+Neo.EraseRectTool.prototype.type = Neo.Painter.TOOLTYPE_ERASERECT;
+
+Neo.EraseRectTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.eraseRect(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ FlipH(左右反転)
+ -------------------------------------------------------------------------
+*/
+
+Neo.FlipHTool = function() {};
+Neo.FlipHTool.prototype = new Neo.EffectToolBase();
+Neo.FlipHTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_H;
+
+Neo.FlipHTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.flipH(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ FlipV(上下反転)
+ -------------------------------------------------------------------------
+*/
+
+Neo.FlipVTool = function() {};
+Neo.FlipVTool.prototype = new Neo.EffectToolBase();
+Neo.FlipVTool.prototype.type = Neo.Painter.TOOLTYPE_FLIP_V;
+
+Neo.FlipVTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.flipV(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ DodgeRect(角取り)
+ -------------------------------------------------------------------------
+*/
+
+Neo.BlurRectTool = function() {};
+Neo.BlurRectTool.prototype = new Neo.EffectToolBase();
+Neo.BlurRectTool.prototype.type = Neo.Painter.TOOLTYPE_BLURRECT;
+
+Neo.BlurRectTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.blurRect(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+Neo.BlurRectTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 0.5;
+ Neo.updateUI();
+ };
+}
+
+/*
+ -------------------------------------------------------------------------
+ Turn(傾け)
+ -------------------------------------------------------------------------
+*/
+
+Neo.TurnTool = function() {};
+Neo.TurnTool.prototype = new Neo.EffectToolBase();
+Neo.TurnTool.prototype.type = Neo.Painter.TOOLTYPE_TURN;
+
+Neo.TurnTool.prototype.upHandler = function(oe) {
+ this.isUpMove = true;
+
+ this.startX = Math.floor(this.startX);
+ this.startY = Math.floor(this.startY);
+ this.endX = Math.floor(this.endX);
+ this.endY = Math.floor(this.endY);
+
+ var x = (this.startX < this.endX) ? this.startX : this.endX;
+ var y = (this.startY < this.endY) ? this.startY : this.endY;
+ var width = Math.abs(this.startX - this.endX) + 1;
+ var height = Math.abs(this.startY - this.endY) + 1;
+
+ if (width > 0 && height > 0) {
+ oe._pushUndo();
+ oe.turn(x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ Merge(レイヤー結合)
+ -------------------------------------------------------------------------
+*/
+
+Neo.MergeTool = function() {};
+Neo.MergeTool.prototype = new Neo.EffectToolBase();
+Neo.MergeTool.prototype.type = Neo.Painter.TOOLTYPE_MERGE;
+
+Neo.MergeTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.merge(ctx, x, y, width, height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ Copy(コピー)
+ -------------------------------------------------------------------------
+*/
+
+Neo.CopyTool = function() {};
+Neo.CopyTool.prototype = new Neo.EffectToolBase();
+Neo.CopyTool.prototype.type = Neo.Painter.TOOLTYPE_COPY;
+
+Neo.CopyTool.prototype.doEffect = function(oe, x, y, width, height) {
+ oe.copy(x, y, width, height);
+ oe.setToolByType(Neo.Painter.TOOLTYPE_PASTE);
+ oe.tool.x = x;
+ oe.tool.y = y;
+ oe.tool.width = width;
+ oe.tool.height = height;
+};
+
+/*
+ -------------------------------------------------------------------------
+ Paste(ペースト)
+ -------------------------------------------------------------------------
+*/
+
+Neo.PasteTool = function() {};
+Neo.PasteTool.prototype = new Neo.ToolBase();
+Neo.PasteTool.prototype.type = Neo.Painter.TOOLTYPE_PASTE;
+
+Neo.PasteTool.prototype.downHandler = function(oe) {
+ this.startX = oe.mouseX;
+ this.startY = oe.mouseY;
+ this.drawCursor(oe);
+};
+
+Neo.PasteTool.prototype.upHandler = function(oe) {
+ oe._pushUndo();
+
+ oe.paste(this.x, this.y, this.width, this.height);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+
+ oe.setToolByType(Neo.Painter.TOOLTYPE_COPY);
+};
+
+Neo.PasteTool.prototype.moveHandler = function(oe) {
+ var dx = Math.floor(oe.mouseX - this.startX);
+ var dy = Math.floor(oe.mouseY - this.startY);
+ oe.tempX = dx;
+ oe.tempY = dy;
+
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ // this.drawCursor(oe);
+};
+
+Neo.PasteTool.prototype.keyDownHandler = function(e) {
+ if (e.keyCode == 27) { //Escでキャンセル
+ var oe = Neo.painter;
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+ oe.setToolByType(Neo.Painter.TOOLTYPE_COPY);
+ }
+};
+
+Neo.PasteTool.prototype.drawCursor = function(oe) {
+ var ctx = oe.destCanvasCtx;
+
+ ctx.save();
+ this.transformForZoom(oe);
+
+ var start = oe.getDestCanvasPosition(this.x, this.y, true);
+ var end = oe.getDestCanvasPosition(this.x + this.width, this.y + this.height, true);
+
+ var x = start.x + oe.tempX * oe.zoom;
+ var y = start.y + oe.tempY * oe.zoom;
+ var width = Math.abs(start.x - end.x);
+ var height = Math.abs(start.y - end.y);
+ oe.drawXORRect(ctx, x, y, width, height);
+ ctx.restore();
+};
+
+/*
+ -------------------------------------------------------------------------
+ Rect(線四角)
+ -------------------------------------------------------------------------
+*/
+
+Neo.RectTool = function() {};
+Neo.RectTool.prototype = new Neo.EffectToolBase();
+Neo.RectTool.prototype.type = Neo.Painter.TOOLTYPE_RECT;
+
+Neo.RectTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.rectMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ RectFill(四角)
+ -------------------------------------------------------------------------
+*/
+
+Neo.RectFillTool = function() {};
+Neo.RectFillTool.prototype = new Neo.EffectToolBase();
+Neo.RectFillTool.prototype.type = Neo.Painter.TOOLTYPE_RECTFILL;
+
+Neo.RectFillTool.prototype.isFill = true;
+Neo.RectFillTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.rectFillMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ Ellipse(線楕円)
+ -------------------------------------------------------------------------
+*/
+
+Neo.EllipseTool = function() {};
+Neo.EllipseTool.prototype = new Neo.EffectToolBase();
+Neo.EllipseTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSE;
+Neo.EllipseTool.prototype.isEllipse = true;
+Neo.EllipseTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.ellipseMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ EllipseFill(楕円)
+ -------------------------------------------------------------------------
+*/
+
+Neo.EllipseFillTool = function() {};
+Neo.EllipseFillTool.prototype = new Neo.EffectToolBase();
+Neo.EllipseFillTool.prototype.type = Neo.Painter.TOOLTYPE_ELLIPSEFILL;
+Neo.EllipseFillTool.prototype.isEllipse = true;
+Neo.EllipseFillTool.prototype.isFill = true;
+Neo.EllipseFillTool.prototype.doEffect = function(oe, x, y, width, height) {
+ var ctx = oe.canvasCtx[oe.current];
+ oe.doFill(ctx, x, y, width, height, oe.ellipseFillMask);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+};
+
+/*
+ -------------------------------------------------------------------------
+ Text(テキスト)
+ -------------------------------------------------------------------------
+*/
+
+Neo.TextTool = function() {};
+Neo.TextTool.prototype = new Neo.ToolBase();
+Neo.TextTool.prototype.type = Neo.Painter.TOOLTYPE_TEXT;
+Neo.TextTool.prototype.isUpMove = false;
+
+Neo.TextTool.prototype.downHandler = function(oe) {
+ this.startX = oe.mouseX;
+ this.startY = oe.mouseY;
+
+ if (Neo.painter.inputText) {
+ Neo.painter.updateInputText();
+
+ var rect = oe.container.getBoundingClientRect();
+ var text = Neo.painter.inputText;
+ var x = oe.rawMouseX - rect.left - 5;
+ var y = oe.rawMouseY - rect.top - 5;
+
+ text.style.left = x + "px";
+ text.style.top = y + "px";
+ text.style.display = "block";
+ text.focus();
+ }
+};
+
+Neo.TextTool.prototype.upHandler = function(oe) {
+};
+
+Neo.TextTool.prototype.moveHandler = function(oe) {};
+Neo.TextTool.prototype.upMoveHandler = function(oe) {};
+Neo.TextTool.prototype.rollOverHandler= function(oe) {};
+Neo.TextTool.prototype.rollOutHandler= function(oe) {};
+
+Neo.TextTool.prototype.keyDownHandler = function(e) {
+ if (e.keyCode == 13) { // Returnで確定
+ e.preventDefault();
+
+ var oe = Neo.painter;
+ var text = oe.inputText;
+ if (text) {
+ oe._pushUndo();
+ this.drawText(oe);
+ oe.updateDestCanvas(0, 0, oe.canvasWidth, oe.canvasHeight, true);
+
+ text.style.display = "none";
+ text.blur();
+ }
+ }
+};
+
+Neo.TextTool.prototype.kill = function(oe) {
+ Neo.painter.hideInputText();
+};
+
+Neo.TextTool.prototype.drawText = function(oe) {
+ var text = oe.inputText;
+
+ // unescape entities
+ //var tmp = document.createElement("textarea");
+ //tmp.innerHTML = text.innerHTML;
+ //var string = tmp.value;
+
+ var string = text.textContent || text.innerText;
+
+ if (string.length <= 0) return;
+ oe.doText(this.startX, this.startY, string, text.style.fontSize);
+};
+
+Neo.TextTool.prototype.loadStates = function() {
+ var reserve = this.getReserve();
+ if (reserve) {
+ Neo.painter.lineWidth = reserve.size;
+ Neo.painter.alpha = 1.0;
+ Neo.updateUI();
+ };
+};
+
+/*
+ -------------------------------------------------------------------------
+ Dummy(何もしない時)
+ -------------------------------------------------------------------------
+*/
+
+Neo.DummyTool = function() {};
+Neo.DummyTool.prototype = new Neo.ToolBase();
+Neo.DummyTool.prototype.type = Neo.Painter.TOOLTYPE_NONE;
+Neo.DummyTool.prototype.isUpMove = false;
+
+Neo.DummyTool.prototype.downHandler = function(oe) {
+};
+
+Neo.DummyTool.prototype.upHandler = function(oe) {
+ oe.popTool();
+};
+
+Neo.DummyTool.prototype.moveHandler = function(oe) {};
+Neo.DummyTool.prototype.upMoveHandler = function(oe) {}
+Neo.DummyTool.prototype.rollOverHandler= function(oe) {}
+Neo.DummyTool.prototype.rollOutHandler= function(oe) {}
+
+'use strict';
+
+Neo.CommandBase = function() {
+};
+Neo.CommandBase.prototype.data;
+Neo.CommandBase.prototype.execute = function() {}
+
+
+/*
+ ---------------------------------------------------
+ ZOOM
+ ---------------------------------------------------
+*/
+Neo.ZoomPlusCommand = function(data) {this.data = data};
+Neo.ZoomPlusCommand.prototype = new Neo.CommandBase();
+Neo.ZoomPlusCommand.prototype.execute = function() {
+ if (this.data.zoom < 12) {
+ this.data.setZoom(this.data.zoom + 1);
+ }
+ Neo.resizeCanvas();
+ Neo.painter.updateDestCanvas();
+};
+
+Neo.ZoomMinusCommand = function(data) {this.data = data};
+Neo.ZoomMinusCommand.prototype = new Neo.CommandBase();
+Neo.ZoomMinusCommand.prototype.execute = function() {
+ if (this.data.zoom >= 2) {
+ this.data.setZoom(this.data.zoom - 1);
+ }
+ Neo.resizeCanvas();
+ Neo.painter.updateDestCanvas();
+};
+
+/*
+ ---------------------------------------------------
+ UNDO
+ ---------------------------------------------------
+*/
+Neo.UndoCommand = function(data) {this.data = data};
+Neo.UndoCommand.prototype = new Neo.CommandBase();
+Neo.UndoCommand.prototype.execute = function() {
+ this.data.undo();
+};
+
+Neo.RedoCommand = function(data) {this.data = data};
+Neo.RedoCommand.prototype = new Neo.CommandBase();
+Neo.RedoCommand.prototype.execute = function() {
+ this.data.redo();
+};
+
+
+Neo.WindowCommand = function(data) {this.data = data};
+Neo.WindowCommand.prototype = new Neo.CommandBase();
+Neo.WindowCommand.prototype.execute = function() {
+ if (Neo.fullScreen) {
+ if (confirm(Neo.translate("ページビュー?"))) {
+ Neo.fullScreen = false;
+ Neo.updateWindow();
+ }
+ } else {
+ if (confirm(Neo.translate("ウィンドウビュー?"))) {
+ Neo.fullScreen = true;
+ Neo.updateWindow();
+ }
+ }
+};
+
+Neo.SubmitCommand = function(data) {this.data = data};
+Neo.SubmitCommand.prototype = new Neo.CommandBase();
+Neo.SubmitCommand.prototype.execute = function() {
+ var board = location.href.replace(/[^/]*$/, '');
+ console.log("submit: " + board);
+ this.data.submit(board);
+};
+
+Neo.CopyrightCommand = function(data) {this.data = data};
+Neo.CopyrightCommand.prototype = new Neo.CommandBase();
+Neo.CopyrightCommand.prototype.execute = function() {
+ var url = "http://github.com/funige/neo/";
+ if (confirm(Neo.translate("PaintBBS NEOは、お絵描きしぃ掲示板 PaintBBS (©2000-2004 しぃちゃん) をhtml5化するプロジェクトです。\n\nPaintBBS NEOのホームページを表示しますか?") + "\n")) {
+ Neo.openURL(url);
+ }
+};
+
+'use strict';
+
+Neo.getModifier = function(e) {
+ if (e.shiftKey) {
+ return 'shift';
+
+ } else if (e.button == 2 || e.ctrlKey || e.altKey || Neo.painter.virtualRight) {
+ return 'right';
+ }
+ return null;
+}
+
+/*
+ -------------------------------------------------------------------------
+ Button
+ -------------------------------------------------------------------------
+*/
+
+Neo.Button = function() {};
+Neo.Button.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.selected = false;
+ this.isMouseDown = false;
+
+ var ref = this;
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onmouseup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onmouseover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onmouseout = function(e) { ref._mouseOutHandler(e); }
+ this.element.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ e.preventDefault();
+ }, true);
+ this.element.addEventListener("touchend", function(e) {
+ ref._mouseUpHandler(e);
+ }, true);
+
+
+ this.element.className = (!this.params.type == "fill") ? "button" : "buttonOff";
+
+ return this;
+};
+
+Neo.Button.prototype._mouseDownHandler = function(e) {
+ if (Neo.painter.isUIPaused()) return;
+ this.isMouseDown = true;
+
+ if ((this.params.type == "fill") && (this.selected == false)) {
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ toolTip.setSelected((this.selected) ? false : true);
+ }
+ Neo.painter.setToolByType(Neo.Painter.TOOLTYPE_FILL);
+ }
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+Neo.Button.prototype._mouseUpHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+
+ if (this.onmouseup) this.onmouseup(this);
+ }
+};
+Neo.Button.prototype._mouseOutHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseout) this.onmouseout(this);
+ }
+};
+Neo.Button.prototype._mouseOverHandler = function(e) {
+ if (this.onmouseover) this.onmouseover(this);
+};
+
+Neo.Button.prototype.setSelected = function(selected) {
+ if (selected) {
+ this.element.className = "buttonOn";
+ } else {
+ this.element.className = "buttonOff";
+ }
+ this.selected = selected;
+};
+
+Neo.Button.prototype.update = function() {
+};
+
+/*
+ -------------------------------------------------------------------------
+ Right Button
+ -------------------------------------------------------------------------
+*/
+
+Neo.RightButton;
+
+Neo.RightButton = function() {};
+Neo.RightButton.prototype = new Neo.Button();
+
+Neo.RightButton.prototype.init = function(name, params) {
+ Neo.Button.prototype.init.call(this, name, params);
+ this.params.type = "right";
+ return this;
+}
+
+Neo.RightButton.prototype._mouseDownHandler = function(e) {
+};
+
+Neo.RightButton.prototype._mouseUpHandler = function(e) {
+ this.setSelected(!this.selected)
+};
+
+Neo.RightButton.prototype._mouseOutHandler = function(e) {
+};
+
+Neo.RightButton.prototype.setSelected = function (selected) {
+ if (selected) {
+ this.element.className = "buttonOn";
+ Neo.painter.virtualRight = true;
+ } else {
+ this.element.className = "buttonOff";
+ Neo.painter.virtualRight = false;
+ }
+ this.selected = selected;
+};
+
+Neo.RightButton.clear = function () {
+ var right = Neo.rightButton;
+ right.setSelected(false);
+};
+
+/*
+ -------------------------------------------------------------------------
+ Fill Button
+ -------------------------------------------------------------------------
+*/
+
+Neo.FillButton;
+
+Neo.FillButton = function() {};
+Neo.FillButton.prototype = new Neo.Button();
+
+Neo.FillButton.prototype.init = function(name, params) {
+ Neo.Button.prototype.init.call(this, name, params);
+ this.params.type = "fill";
+ return this;
+}
+
+/*
+ -------------------------------------------------------------------------
+ ColorTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.colorTips = [];
+
+Neo.ColorTip = function() {};
+Neo.ColorTip.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+
+ this.selected = (this.name == "color1") ? true : false;
+ this.isMouseDown = false;
+
+ var ref = this;
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onmouseup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onmouseover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onmouseout = function(e) { ref._mouseOutHandler(e); }
+ this.element.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ e.preventDefault();
+ }, true);
+ this.element.addEventListener("touchend", function(e) {
+ ref._mouseUpHandler(e);
+ }, true);
+
+ this.element.className = "colorTipOff";
+
+ var index = parseInt(this.name.slice(5)) - 1;
+ this.element.style.left = (index % 2) ? "0px" : "26px";
+ this.element.style.top = Math.floor(index / 2) * 21 + "px";
+
+ // base64 ColorTip.png
+ this.element.innerHTML = "<img style='max-width:44px;' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAAASCAYAAAAg9DzcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANklEQVRIx+3OAQkAMADDsO3+Pe8qCj+0Akq6bQFqS2wTCpwE+R4IiyVYsGDBggULfirBgn8HX7BzCRwDx1QeAAAAAElFTkSuQmCC' />"
+
+ this.setColor(Neo.config.colors[params.index - 1]);
+
+ this.setSelected(this.selected);
+ Neo.colorTips.push(this);
+};
+
+Neo.ColorTip.prototype._mouseDownHandler = function(e) {
+ if (Neo.painter.isUIPaused()) return;
+ this.isMouseDown = true;
+
+ for (var i = 0; i < Neo.colorTips.length; i++) {
+ var colorTip = Neo.colorTips[i];
+ if (this == colorTip) {
+ switch (Neo.getModifier(e)) {
+ case 'shift':
+ this.setColor(Neo.config.colors[this.params.index - 1]);
+ break;
+ case 'right':
+ this.setColor(Neo.painter.foregroundColor);
+ break;
+ }
+
+// if (e.shiftKey) {
+// this.setColor(Neo.config.colors[this.params.index - 1]);
+// } else if (e.button == 2 || e.ctrlKey || e.altKey ||
+// Neo.painter.virtualRight) {
+// this.setColor(Neo.painter.foregroundColor);
+// }
+ }
+ colorTip.setSelected(this == colorTip) ? true : false;
+ }
+ Neo.painter.setColor(this.color);
+ Neo.updateUIColor(true, false);
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+Neo.ColorTip.prototype._mouseUpHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseup) this.onmouseup(this);
+ }
+};
+Neo.ColorTip.prototype._mouseOutHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseout) this.onmouseout(this);
+ }
+};
+Neo.ColorTip.prototype._mouseOverHandler = function(e) {
+ if (this.onmouseover) this.onmouseover(this);
+};
+
+Neo.ColorTip.prototype.setSelected = function(selected) {
+ if (selected) {
+ this.element.className = "colorTipOn";
+ } else {
+ this.element.className = "colorTipOff";
+ }
+ this.selected = selected;
+};
+
+Neo.ColorTip.prototype.setColor = function(color) {
+ this.color = color;
+ this.element.style.backgroundColor = color;
+};
+
+Neo.ColorTip.getCurrent = function() {
+ for (var i = 0; i < Neo.colorTips.length; i++) {
+ var colorTip = Neo.colorTips[i];
+ if (colorTip.selected) return colorTip;
+ }
+ return null;
+};
+
+/*
+ -------------------------------------------------------------------------
+ ToolTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.toolTips = [];
+Neo.toolButtons = [];
+
+Neo.ToolTip = function() {};
+
+Neo.ToolTip.prototype.prevMode = -1;
+
+Neo.ToolTip.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.params.type = this.element.id;
+ this.name = name;
+ this.mode = 0;
+
+ this.isMouseDown = false;
+
+ var ref = this;
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.onmouseup = function(e) { ref._mouseUpHandler(e); }
+ this.element.onmouseover = function(e) { ref._mouseOverHandler(e); }
+ this.element.onmouseout = function(e) { ref._mouseOutHandler(e); }
+ this.element.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ e.preventDefault();
+ }, true);
+ this.element.addEventListener("touchend", function(e) {
+ ref._mouseUpHandler(e);
+ }, true);
+
+ this.selected = (this.params.type == "pen") ? true : false;
+ this.setSelected(this.selected);
+
+ this.element.innerHTML = "<canvas width=46 height=18></canvas><div class='label'></div>";
+ this.canvas = this.element.getElementsByTagName('canvas')[0];
+ this.label = this.element.getElementsByTagName('div')[0];
+
+ this.update();
+ return this;
+};
+
+Neo.ToolTip.prototype._mouseDownHandler = function(e) {
+ this.isMouseDown = true;
+
+ if (this.isTool) {
+ if (this.selected == false) {
+ for (var i = 0; i < Neo.toolButtons.length; i++) {
+ var toolTip = Neo.toolButtons[i];
+ toolTip.setSelected((this == toolTip) ? true : false);
+ }
+
+ } else {
+ var length = this.toolStrings.length;
+ if (Neo.getModifier(e) == "right") {
+ this.mode--;
+ if (this.mode < 0) this.mode = length - 1;
+
+ } else {
+ this.mode++;
+ if (this.mode >= length) this.mode = 0;
+ }
+ }
+ Neo.painter.setToolByType(this.tools[this.mode]);
+ this.update();
+ }
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+
+Neo.ToolTip.prototype._mouseUpHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseup) this.onmouseup(this);
+ }
+};
+
+Neo.ToolTip.prototype._mouseOutHandler = function(e) {
+ if (this.isMouseDown) {
+ this.isMouseDown = false;
+ if (this.onmouseout) this.onmouseout(this);
+ }
+};
+Neo.ToolTip.prototype._mouseOverHandler = function(e) {
+ if (this.onmouseover) this.onmouseover(this);
+};
+
+Neo.ToolTip.prototype.setSelected = function(selected) {
+ if (this.fixed) {
+ this.element.className = "toolTipFixed";
+
+ } else {
+ if (selected) {
+ this.element.className = "toolTipOn";
+ } else {
+ this.element.className = "toolTipOff";
+ }
+ }
+ this.selected = selected;
+};
+
+Neo.ToolTip.prototype.update = function() {};
+
+Neo.ToolTip.prototype.draw = function(c) {
+ if (this.hasTintImage) {
+ if (typeof c != "string") c = Neo.painter.getColorString(c);
+ var ctx = this.canvas.getContext("2d");
+
+ if (this.prevMode != this.mode) {
+ this.prevMode = this.mode;
+
+ var img = new Image();
+ img.src = this.toolIcons[this.mode];
+ img.onload = function() {
+ var ref = this;
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ this.drawTintImage(ctx, img, c, 0, 0);
+ }.bind(this);
+
+ } else {
+ this.tintImage(ctx, c);
+ }
+ }
+};
+
+Neo.ToolTip.prototype.drawTintImage = function(ctx, img, c, x, y) {
+ ctx.drawImage(img, x, y);
+ this.tintImage(ctx, c);
+};
+
+Neo.ToolTip.prototype.tintImage = function(ctx, c) {
+ c = (Neo.painter.getColor(c) & 0xffffff);
+
+ var imageData = ctx.getImageData(0, 0, 46, 18);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+
+ for (var i = 0; i < buf32.length; i++) {
+ var a = buf32[i] & 0xff000000;
+ if (a) {
+ buf32[i] = buf32[i] & a | c;
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+};
+
+Neo.ToolTip.bezier = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAT0lEQVRIx+3SQQoAIAhE0en+h7ZVEEKBZrX5b5sjKknAkRYpNslaMLPq44ZI9wwHs0vMQ/v87u0Kk8xfsaI242jbMdjPi5Y0r/zTAAAAD3UOjRf9jcO4sgAAAABJRU5ErkJggg==";
+Neo.ToolTip.blur = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAASUlEQVRIx+3VMQ4AIAgEQeD/f8bWWBnJYUh2SgtgK82G8/MhzVKwxOtTLgIUx6tDout4laiPIICA0Qj4bXxAy0+8LZP9yACAJwsqkggS55eiZgAAAABJRU5ErkJggg==";
+Neo.ToolTip.blurrect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAX0lEQVRIx+2XQQ4AEAwEt+I7/v+8Org6lJKt6NzLjjYE8DAKtLpYoDeCCCC7tYUd3ru2qQOzDTyndhJzB6KSAmxSgM0fAlGuzBnmlziqxB8jFJkUYJMCbAQYPxt2kF06fvYKgjPBO/IAAAAASUVORK5CYII=";
+Neo.ToolTip.brush = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQUlEQVRIx2NgGOKAEcb4z8CweRA4xpdUPSxofJ8BdP8WcjQxDaCDqQLQY4CsUBgFo2AUjIJRMApGwSgYBaNgZAIA0CoDwDbZu8oAAAAASUVORK5CYII=";
+Neo.ToolTip.burn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAPklEQVRIx+3PMRIAMAQAQbzM0/0sKZPeiDG57TQ4keH0Htx9VR+MCM1vOezl8xUsv4IAAkYjoBsB3QgAgL9tYXgF19rh9yoAAAAASUVORK5CYII=";
+Neo.ToolTip.copy = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XMQoAIAwDU/E7/v95Orh2KMUSC7m5Qs6AUqAxG1gzOLirwxhgmXOjOlg1oQY8sjf2mvYNSICNBNhIgE3oH/jlzfdo34AE2EiATXsBA+5mww6S5QASDwSGMt8ouwAAAABJRU5ErkJggg==";
+Neo.ToolTip.copy2 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAN0lEQVRIx+3PwQkAIBADwdPKt3MtQVCOPNz5B7JV0pNxOwRW9zng+G92n+hmQJoBaQakGSBJf9tyBgQUV/fKCAAAAABJRU5ErkJggg==";
+Neo.ToolTip.ellipse = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAATklEQVRIx+2VMQ4AIAgD6/8fjbOJi1LFmt4OPQ0KIE7LNgggCBLbHkuFM9lM+Om+QwDjpksyb4tT86vlvzgEbYxefQPyv5D8HjDGGGOk6b3jJ+lYubd8AAAAAElFTkSuQmCC";
+Neo.ToolTip.ellipsefill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAVUlEQVRIx+2VURIAEAgFc/9D5waSHpV5+43ZHRMizRnRA1REARLHHq6NCFl01Nail+LeEDMgU34nYhlQQd6K+PsGKkSEZyArBPoK3Y6K/AOEEEJIayZHbhIKjkZrFwAAAABJRU5ErkJggg==";
+Neo.ToolTip.eraser = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAABQElEQVRIx+1WQY7CMAwcI37Cad+yXOgH4Gu8gAt9CtrDirfMHjZJbbcktVSpQnROSeMkY3vsFHhzSG3xfLpz/JVmG0mIqDkIMcc6+7Kejx6fdb0dq7w09rVFkrjejrMOunQ9vg7f/5QEIAd6E1Eo38WF8fF7n8sdALCrLerIzoFI4sI0Vtv1SYZ8CVbeF7tzF7JugIkVkxOauc6CIe8842S+XmMfsq7TN9LRTngZmTmVD4SrnzYaGYhFoxCWgajXuMjYGTuJ3dlwIBIN3U0cUVqLXCs5E7YeVsvAYJul5HWeLUhL3EpstQwooqoOTEHDOebpMn7ngkUsg3RotU8X1MkuVDrYohkIupC0YArX6T+PfX3kcbQLNV/iCKi6EB3xqXdAZ0JKthZ8B0QEl673NIEX/0I/z36Rf6ENGzZ8EP4A8Lp+9e9VWC4AAAAASUVORK5CYII=";
+Neo.ToolTip.flip = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAZklEQVRIx+2XQQoAIAgE1+g7/f95degWHSyTTXDOhTsSiUBgOtCq8mD3DiOA3NxTCVgKaLA0qHiFOsHSnC8ELKQAmxRgE15APQfWv9pzLjwX+CXsjvBPKAXYpACb8AICzM2GHeSWAfVOCIiJuQ9tAAAAAElFTkSuQmCC";
+Neo.ToolTip.freehand = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAdUlEQVRIx+2WUQrAMAhD3dj9r+y+VoSyLhYDynzQv1qiJlCR4hzeAhVRsiC3Jkj0c5hN7Lx7IQ9SphLE1ICdwko420purEWQuywN3pqxgcw2+WwAtU1GzoqiLZNwZBvMAIcO8y3YKUO8mkbmjPzjK9E0TUPjBoeyLAS0usjLAAAAAElFTkSuQmCC";
+Neo.ToolTip.line = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAU0lEQVRIx+2UQQ4AIAjD8P+PxivRGDQC47C+oN1hIgTLQAt4qIga2c23XYAVPkm3CVhlb4ShAa/rQgMi1i0NyFg3LaBq3bAA1LpfAd7/EkIIIR2YXFYSCpWS8w8AAAAASUVORK5CYII=";
+Neo.ToolTip.merge = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAW0lEQVRIx+2XQQrAQAgDx9Lv9JF9+e6h54IINlgyZ4UMOYgwmAXXmRxc3WECorJ3dAfrJtXAC7c6PPygAQuosYAaC6hJ3YHqlfyC8Q1YQI0F1IwXCHg+G3WQKhvwgwUFmFyYbwAAAABJRU5ErkJggg==";
+Neo.ToolTip.pen = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAK0lEQVRIx+3OsQkAMAwDQXn/oe3WfSAEctd9I5TA32pHJ/3AoTpfAQCAGwaa5AICJLKWSQAAAABJRU5ErkJggg==";
+Neo.ToolTip.rect = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAQElEQVRIx+3TMQ4AIAhD0WK8/5VxdcIYY8rw3wok7YAEr6iGKaU74BY0ro+6FKhyDHe4VxRwm6eFLn8AAADwwQIwTQgGo9ZMywAAAABJRU5ErkJggg==";
+Neo.ToolTip.rectfill = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAANElEQVRIx+3PIQ4AIBADwcL//3xYBMEgLiQztmab0GvcxkqqO3ALPbbO7rBXDnRzAADgYwvqDwIMJlGb5QAAAABJRU5ErkJggg==";
+Neo.ToolTip.text = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAcUlEQVRIx+2VwQ7AIAhDy7L//2V2WmIYg+ky2KEv8aCCqYQqQMgrJNpUQMXEKKDmAPHyspgSrBBvLZu3cQqZEdwhfusq0KdkVR5HlFfBvpI0mtIzeusFot7vFPqYuzZYMXUFlzc+qrIn7tf/ACGEkIwDlEQ94YZjzcgAAAAASUVORK5CYII=";
+Neo.ToolTip.tone = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAATCAYAAADWOo4fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAO0lEQVRIx+3PIQ4AMAgEwaP//zNVVZUELiQ7CgWstFy8IaVsPhT1Lb/T+fQEAtwIcCPAjQC39QEAgJIL6DQCFhAqsRkAAAAASUVORK5CYII=";
+
+/*
+ -------------------------------------------------------------------------
+ PenTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.penTip;
+
+Neo.PenTip = function() {};
+Neo.PenTip.prototype = new Neo.ToolTip();
+
+Neo.PenTip.prototype.tools = [Neo.Painter.TOOLTYPE_PEN,
+ Neo.Painter.TOOLTYPE_BRUSH,
+ Neo.Painter.TOOLTYPE_TEXT];
+
+Neo.PenTip.prototype.hasTintImage = true;
+Neo.PenTip.prototype.toolIcons = [Neo.ToolTip.pen,
+ Neo.ToolTip.brush,
+ Neo.ToolTip.text];
+
+Neo.PenTip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("鉛筆"),
+ Neo.translate("水彩"),
+ Neo.translate("テキスト")];
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.PenTip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ this.draw(Neo.painter.foregroundColor);
+ if (this.label) {
+ this.label.innerHTML = this.toolStrings[this.mode];
+ }
+};
+
+/*
+ -------------------------------------------------------------------------
+ Pen2Tip
+ -------------------------------------------------------------------------
+*/
+
+Neo.pen2Tip;
+
+Neo.Pen2Tip = function() {};
+Neo.Pen2Tip.prototype = new Neo.ToolTip();
+
+Neo.Pen2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_TONE,
+ Neo.Painter.TOOLTYPE_BLUR,
+ Neo.Painter.TOOLTYPE_DODGE,
+ Neo.Painter.TOOLTYPE_BURN];
+
+Neo.Pen2Tip.prototype.hasTintImage = true;
+Neo.Pen2Tip.prototype.toolIcons = [Neo.ToolTip.tone,
+ Neo.ToolTip.blur,
+ Neo.ToolTip.burn,
+ Neo.ToolTip.burn];
+
+Neo.Pen2Tip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("トーン"),
+ Neo.translate("ぼかし"),
+ Neo.translate("覆い焼き"),
+ Neo.translate("焼き込み")];
+
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.Pen2Tip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ switch (this.tools[this.mode]) {
+ case Neo.Painter.TOOLTYPE_TONE:
+ this.drawTone(Neo.painter.foregroundColor);
+ break;
+
+ case Neo.Painter.TOOLTYPE_DODGE:
+ this.draw(0xffc0c0c0);
+ break;
+
+ case Neo.Painter.TOOLTYPE_BURN:
+ this.draw(0xff404040);
+ break;
+
+ default:
+ this.draw(Neo.painter.foregroundColor);
+ break;
+ }
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+Neo.Pen2Tip.prototype.drawTone = function() {
+ var ctx = this.canvas.getContext("2d");
+
+ var imageData = ctx.getImageData(0, 0, 46, 18);
+ var buf32 = new Uint32Array(imageData.data.buffer);
+ var buf8 = new Uint8ClampedArray(imageData.data.buffer);
+ var c = Neo.painter.getColor() | 0xff000000;
+ var a = Math.floor(Neo.painter.alpha * 255);
+ var toneData = Neo.painter.getToneData(a);
+
+ for (var j = 0; j < 18; j++) {
+ for (var i = 0; i < 46; i++) {
+ if (j >= 1 && j < 12 &&
+ i >= 2 && i < 26 &&
+ toneData[(i%4) + (j%4) * 4]) {
+ buf32[j * 46 + i] = c;
+
+ } else {
+ buf32[j * 46 + i] = 0;
+ }
+ }
+ }
+ imageData.data.set(buf8);
+ ctx.putImageData(imageData, 0, 0);
+
+ this.prevMode = this.mode;
+};
+
+
+/*
+ -------------------------------------------------------------------------
+ EraserTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.eraserTip;
+
+Neo.EraserTip = function() {};
+Neo.EraserTip.prototype = new Neo.ToolTip();
+
+Neo.EraserTip.prototype.tools = [Neo.Painter.TOOLTYPE_ERASER,
+ Neo.Painter.TOOLTYPE_ERASERECT,
+ Neo.Painter.TOOLTYPE_ERASEALL];
+
+Neo.EraserTip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("消しペン"),
+ Neo.translate("消し四角"),
+ Neo.translate("全消し")];
+
+ this.drawOnce = false;
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.EraserTip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ if (this.drawOnce == false) {
+ this.draw();
+ this.drawOnce = true;
+ }
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+Neo.EraserTip.prototype.draw = function() {
+ var ctx = this.canvas.getContext("2d");
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ var img = new Image();
+
+ img.src = Neo.ToolTip.eraser;
+ img.onload = function() {
+ ctx.drawImage(img, 0, 0);
+ };
+};
+
+/*
+ -------------------------------------------------------------------------
+ EffectTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.effectTip;
+
+Neo.EffectTip = function() {};
+Neo.EffectTip.prototype = new Neo.ToolTip();
+
+Neo.EffectTip.prototype.tools = [Neo.Painter.TOOLTYPE_RECTFILL,
+ Neo.Painter.TOOLTYPE_RECT,
+ Neo.Painter.TOOLTYPE_ELLIPSEFILL,
+ Neo.Painter.TOOLTYPE_ELLIPSE];
+
+Neo.EffectTip.prototype.hasTintImage = true;
+Neo.EffectTip.prototype.toolIcons = [Neo.ToolTip.rectfill,
+ Neo.ToolTip.rect,
+ Neo.ToolTip.ellipsefill,
+ Neo.ToolTip.ellipse];
+
+Neo.EffectTip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("四角"),
+ Neo.translate("線四角"),
+ Neo.translate("楕円"),
+ Neo.translate("線楕円")];
+
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.EffectTip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ this.draw(Neo.painter.foregroundColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+/*
+ -------------------------------------------------------------------------
+ Effect2Tip
+ -------------------------------------------------------------------------
+*/
+
+Neo.effect2Tip;
+
+Neo.Effect2Tip = function() {};
+Neo.Effect2Tip.prototype = new Neo.ToolTip();
+
+Neo.Effect2Tip.prototype.tools = [Neo.Painter.TOOLTYPE_COPY,
+ Neo.Painter.TOOLTYPE_MERGE,
+ Neo.Painter.TOOLTYPE_BLURRECT,
+ Neo.Painter.TOOLTYPE_FLIP_H,
+ Neo.Painter.TOOLTYPE_FLIP_V,
+ Neo.Painter.TOOLTYPE_TURN];
+
+Neo.Effect2Tip.prototype.hasTintImage = true;
+Neo.Effect2Tip.prototype.toolIcons = [Neo.ToolTip.copy,
+ Neo.ToolTip.merge,
+ Neo.ToolTip.blurrect,
+ Neo.ToolTip.flip,
+ Neo.ToolTip.flip,
+ Neo.ToolTip.flip];
+
+Neo.Effect2Tip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("コピー"),
+ Neo.translate("レイヤ結合"),
+ Neo.translate("角取り"),
+ Neo.translate("左右反転"),
+ Neo.translate("上下反転"),
+ Neo.translate("傾け")];
+
+ this.isTool = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+
+ this.img = document.createElement("img");
+ this.img.src = Neo.ToolTip.copy2;
+ this.element.appendChild(this.img);
+ return this;
+};
+
+Neo.Effect2Tip.prototype.update = function() {
+ for (var i = 0; i < this.tools.length; i++) {
+ if (Neo.painter.tool.type == this.tools[i]) this.mode = i;
+ }
+
+ this.draw(Neo.painter.foregroundColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+/*
+ -------------------------------------------------------------------------
+ MaskTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.maskTip;
+
+Neo.MaskTip = function() {};
+Neo.MaskTip.prototype = new Neo.ToolTip();
+
+Neo.MaskTip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("通常"),
+ Neo.translate("マスク"),
+ Neo.translate("逆マスク"),
+ Neo.translate("加算"),
+ Neo.translate("逆加算")];
+
+ this.fixed = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.MaskTip.prototype._mouseDownHandler = function(e) {
+ this.isMouseDown = true;
+
+ if (Neo.getModifier(e) == "right") {
+ Neo.painter.maskColor = Neo.painter.foregroundColor;
+
+ } else {
+ var length = this.toolStrings.length;
+ this.mode++;
+ if (this.mode >= length) this.mode = 0;
+ Neo.painter.maskType = this.mode;
+ }
+ this.update();
+
+ if (this.onmousedown) this.onmousedown(this);
+}
+
+Neo.MaskTip.prototype.update = function() {
+ this.draw(Neo.painter.maskColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+Neo.MaskTip.prototype.draw = function(c) {
+ if (typeof c != "string") c = Neo.painter.getColorString(c);
+
+ var ctx = this.canvas.getContext("2d");
+ ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ ctx.fillStyle = c;
+ ctx.fillRect(1, 1, 43, 9);
+};
+
+/*
+ -------------------------------------------------------------------------
+ DrawTip
+ -------------------------------------------------------------------------
+*/
+
+Neo.drawTip;
+
+Neo.DrawTip = function() {};
+Neo.DrawTip.prototype = new Neo.ToolTip();
+
+Neo.DrawTip.prototype.hasTintImage = true;
+Neo.DrawTip.prototype.toolIcons = [Neo.ToolTip.freehand,
+ Neo.ToolTip.line,
+ Neo.ToolTip.bezier];
+
+Neo.DrawTip.prototype.init = function(name, params) {
+ this.toolStrings = [Neo.translate("手書き"),
+ Neo.translate("直線"),
+ Neo.translate("BZ曲線")];
+
+ this.fixed = true;
+ Neo.ToolTip.prototype.init.call(this, name, params);
+ return this;
+};
+
+Neo.DrawTip.prototype._mouseDownHandler = function(e) {
+ this.isMouseDown = true;
+
+ var length = this.toolStrings.length;
+
+ if (Neo.getModifier(e) == "right") {
+ this.mode--;
+ if (this.mode < 0) this.mode = length - 1;
+
+ } else {
+ this.mode++;
+ if (this.mode >= length) this.mode = 0;
+ }
+ Neo.painter.drawType = this.mode;
+ this.update();
+
+ if (this.onmousedown) this.onmousedown(this);
+}
+
+Neo.DrawTip.prototype.update = function() {
+ this.mode = Neo.painter.drawType;
+ this.draw(Neo.painter.foregroundColor);
+ this.label.innerHTML = this.toolStrings[this.mode];
+};
+
+/*
+ -------------------------------------------------------------------------
+ ColorSlider
+ -------------------------------------------------------------------------
+*/
+
+Neo.sliders = [];
+
+Neo.ColorSlider = function() {};
+
+Neo.ColorSlider.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.isMouseDown = false;
+ this.value = 0;
+ this.type = this.params.type;
+
+ this.element.className = "colorSlider";
+ this.element.innerHTML = "<div class='slider'></div><div class='label'></div>";
+ this.element.innerHTML += "<div class='hit'></div>";
+
+ this.slider = this.element.getElementsByClassName('slider')[0];
+ this.label = this.element.getElementsByClassName('label')[0];
+ this.hit = this.element.getElementsByClassName('hit')[0];
+ this.hit['data-slider'] = params.type;
+
+ switch (this.type) {
+ case Neo.SLIDERTYPE_RED:
+ this.prefix = "R";
+ this.slider.style.backgroundColor = "#fa9696";
+ break;
+ case Neo.SLIDERTYPE_GREEN:
+ this.prefix = "G";
+ this.slider.style.backgroundColor = "#82f238";
+ break;
+ case Neo.SLIDERTYPE_BLUE:
+ this.prefix = "B";
+ this.slider.style.backgroundColor = "#8080ff";
+ break;
+ case Neo.SLIDERTYPE_ALPHA:
+ this.prefix = "A";
+ this.slider.style.backgroundColor = "#aaaaaa";
+ this.value = 255;
+ break;
+ }
+
+ this.update();
+ return this;
+};
+
+Neo.ColorSlider.prototype.downHandler = function(x, y) {
+ if (Neo.painter.isShiftDown) {
+ this.shift(x, y);
+
+ } else {
+ this.slide(x, y);
+ }
+};
+
+Neo.ColorSlider.prototype.moveHandler = function(x, y) {
+ this.slide(x, y);
+ //event.preventDefault();
+};
+
+Neo.ColorSlider.prototype.upHandler = function(x, y) {
+};
+
+Neo.ColorSlider.prototype.shift = function(x, y) {
+ var value;
+ if (x >= 0 && x < 60 && y >= 0 && y <= 15) {
+ var v = Math.floor((x - 5) * 5.0);
+ var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0;
+
+ value = Math.max(Math.min(v, 255), min);
+ if (this.value > value || this.value == 255) {
+ this.value--;
+ } else {
+ this.value++;
+ }
+ this.value = Math.max(Math.min(this.value, 255), min);
+ this.value0 = this.value;
+ this.x0 = x;
+ }
+
+ if (this.type == Neo.SLIDERTYPE_ALPHA) {
+ Neo.painter.alpha = this.value / 255.0;
+ this.update();
+ Neo.updateUIColor(false, false);
+
+ } else {
+ var r = Neo.sliders[Neo.SLIDERTYPE_RED].value;
+ var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value;
+ var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value;
+
+ Neo.painter.setColor(r<<16 | g<<8 | b);
+ Neo.updateUIColor(true, true);
+ }
+};
+
+Neo.ColorSlider.prototype.slide = function(x, y) {
+ var value;
+ if (x >= 0 && x < 60 && y >= 0 && y <= 15) {
+ var v = Math.floor((x - 5) * 5.0);
+ value = Math.round(v / 5) * 5;
+
+ this.value0 = value;
+ this.x0 = x;
+
+ } else {
+ var d = (x - this.x0) / 3.0;
+ value = this.value0 + d;
+ }
+
+ var min = (this.type == Neo.SLIDERTYPE_ALPHA) ? 1 : 0;
+ this.value = Math.max(Math.min(value, 255), min);
+
+ if (this.type == Neo.SLIDERTYPE_ALPHA) {
+ Neo.painter.alpha = this.value / 255.0;
+ this.update();
+ Neo.updateUIColor(false, false);
+
+ } else {
+ var r = Neo.sliders[Neo.SLIDERTYPE_RED].value;
+ var g = Neo.sliders[Neo.SLIDERTYPE_GREEN].value;
+ var b = Neo.sliders[Neo.SLIDERTYPE_BLUE].value;
+ var color = (r<<16 | g<<8 | b);
+
+ var colorTip = Neo.ColorTip.getCurrent()
+ if (colorTip) {
+ colorTip.setColor(Neo.painter.getColorString(color))
+ }
+
+ Neo.painter.setColor(color);
+ // Neo.updateUIColor(true, true);
+ }
+};
+
+Neo.ColorSlider.prototype.update = function() {
+ var color = Neo.painter.getColor();
+ var alpha = Neo.painter.alpha * 255;
+
+ switch (this.type) {
+ case Neo.SLIDERTYPE_RED: this.value = (color & 0x0000ff); break;
+ case Neo.SLIDERTYPE_GREEN: this.value = (color & 0x00ff00) >> 8; break;
+ case Neo.SLIDERTYPE_BLUE: this.value = (color & 0xff0000) >> 16; break;
+ case Neo.SLIDERTYPE_ALPHA: this.value = alpha; break;
+ }
+
+ var width = this.value * 49.0 / 255.0;
+ width = Math.max(Math.min(48, width), 1);
+
+ this.slider.style.width = width.toFixed(2) + "px";
+ this.label.innerHTML = this.prefix + this.value.toFixed(0);
+};
+
+/*
+ -------------------------------------------------------------------------
+ SizeSlider
+ -------------------------------------------------------------------------
+*/
+
+Neo.SizeSlider = function() {};
+
+Neo.SizeSlider.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.isMouseDown = false;
+ this.value = this.value0 = 1;
+
+ this.element.className = "sizeSlider";
+ this.element.innerHTML = "<div class='slider'></div><div class='label'></div>";
+ this.element.innerHTML += "<div class='hit'></div>"
+
+ this.slider = this.element.getElementsByClassName('slider')[0];
+ this.label = this.element.getElementsByClassName('label')[0];
+ this.hit = this.element.getElementsByClassName('hit')[0];
+ this.hit['data-slider'] = params.type;
+
+ this.slider.style.backgroundColor = Neo.painter.foregroundColor;
+ this.update();
+ return this;
+};
+
+Neo.SizeSlider.prototype.downHandler = function(x, y) {
+ if (Neo.painter.isShiftDown) {
+ this.shift(x, y);
+
+ } else {
+ this.value0 = this.value;
+ this.y0 = y;
+ this.slide(x, y);
+ }
+};
+
+Neo.SizeSlider.prototype.moveHandler = function(x, y) {
+ this.slide(x, y);
+ //event.preventDefault();
+};
+
+Neo.SizeSlider.prototype.upHandler = function(x, y) {
+};
+
+Neo.SizeSlider.prototype.shift = function(x, y) {
+ var value0 = Neo.painter.lineWidth;
+ var value;
+
+ if (!Neo.painter.tool.alt) {
+ var v = Math.floor((y - 4) * 30.0 / 33.0);
+
+ value = Math.max(Math.min(v, 30), 1);
+ if (value0 > value || value0 == 30) {
+ value0--;
+ } else {
+ value0++;
+ }
+ this.setSize(value0);
+ }
+};
+
+Neo.SizeSlider.prototype.slide = function(x, y) {
+ var value;
+ if (!Neo.painter.tool.alt) {
+ if (x >= 0 && x < 48 && y >= 0 && y < 41) {
+ var v = Math.floor((y - 4) * 30.0 / 33.0);
+ value = v;
+
+ this.value0 = value;
+ this.y0 = y;
+
+ } else {
+ var d = (y - this.y0) / 7.0;
+ value = this.value0 + d;
+ }
+ } else {
+ // Ctrl+Alt+ドラッグでサイズ変更するとき
+ var d = y - this.y0;
+ value = this.value0 + d;
+ }
+
+ value = Math.max(Math.min(value, 30), 1);
+ this.setSize(value);
+};
+
+Neo.SizeSlider.prototype.setSize = function(value) {
+ value = Math.round(value);
+ Neo.painter.lineWidth = Math.max(Math.min(30, value), 1);
+
+ var tool = Neo.painter.getCurrentTool();
+ if (tool) {
+ if (tool.type == Neo.Painter.TOOLTYPE_BRUSH) {
+ Neo.painter.alpha = tool.getAlpha();
+ Neo.sliders[Neo.SLIDERTYPE_ALPHA].update();
+
+ } else if (tool.type == Neo.Painter.TOOLTYPE_TEXT) {
+ Neo.painter.updateInputText();
+ }
+ }
+ this.update();
+};
+
+Neo.SizeSlider.prototype.update = function() {
+ this.value = Neo.painter.lineWidth;
+
+ var height = this.value * 33.0 / 30.0;
+ height = Math.max(Math.min(34, height), 1);
+
+ this.slider.style.height = height.toFixed(2) + "px";
+ this.label.innerHTML = this.value + "px";
+ this.slider.style.backgroundColor = Neo.painter.foregroundColor;
+};
+
+/*
+ -------------------------------------------------------------------------
+ LayerControl
+ -------------------------------------------------------------------------
+*/
+
+Neo.LayerControl = function() {};
+Neo.LayerControl.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+ this.isMouseDown = false;
+
+ var ref = this;
+
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ e.preventDefault();
+ }, true);
+
+ this.element.className = "layerControl";
+
+ var layerStrings = [Neo.translate("Layer0"),
+ Neo.translate("Layer1")];
+
+ this.element.innerHTML =
+ "<div class='bg'></div><div class='label0'>" + layerStrings[0] +
+ "</div><div class='label1'>" + layerStrings[1] +
+ "</div><div class='line1'></div><div class='line0'></div>";
+
+ this.bg = this.element.getElementsByClassName('bg')[0];
+ this.label0 = this.element.getElementsByClassName('label0')[0];
+ this.label1 = this.element.getElementsByClassName('label1')[0];
+ this.line0 = this.element.getElementsByClassName('line0')[0];
+ this.line1 = this.element.getElementsByClassName('line1')[0];
+
+ this.line0.style.display = "none";
+ this.line1.style.display = "none";
+ this.label1.style.display = "none";
+
+ this.update();
+ return this;
+};
+
+Neo.LayerControl.prototype._mouseDownHandler = function(e) {
+ if (Neo.getModifier(e) == "right") {
+ var visible = Neo.painter.visible[Neo.painter.current];
+ Neo.painter.visible[Neo.painter.current] = (visible) ? false : true;
+
+ } else {
+ var current = Neo.painter.current;
+ Neo.painter.current = (current) ? 0 : 1
+ }
+ Neo.painter.updateDestCanvas(0, 0, Neo.painter.canvasWidth, Neo.painter.canvasHeight);
+ if (Neo.painter.tool.type == Neo.Painter.TOOLTYPE_PASTE) {
+ Neo.painter.tool.drawCursor(Neo.painter);
+ }
+ this.update();
+
+ if (this.onmousedown) this.onmousedown(this);
+};
+
+Neo.LayerControl.prototype.update = function() {
+ this.label0.style.display = (Neo.painter.current == 0) ? "block" : "none";
+ this.label1.style.display = (Neo.painter.current == 1) ? "block" : "none";
+ this.line0.style.display = (Neo.painter.visible[0]) ? "none" : "block";
+ this.line1.style.display = (Neo.painter.visible[1]) ? "none" : "block";
+};
+
+/*
+ -------------------------------------------------------------------------
+ ReserveControl
+ -------------------------------------------------------------------------
+*/
+Neo.reserveControls = [];
+
+Neo.ReserveControl = function() {};
+Neo.ReserveControl.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+
+ var ref = this;
+
+ this.element.onmousedown = function(e) { ref._mouseDownHandler(e); }
+ this.element.addEventListener("touchstart", function(e) {
+ ref._mouseDownHandler(e);
+ e.preventDefault();
+ }, true);
+
+ this.element.className = "reserve";
+
+ var index = parseInt(this.name.slice(7)) - 1;
+ this.element.style.top = "1px";
+ this.element.style.left = (index * 15 + 2) + "px";
+
+ this.reserve = Neo.clone(Neo.config.reserves[index]);
+ this.update();
+
+ Neo.reserveControls.push(this);
+ return this;
+};
+
+Neo.ReserveControl.prototype._mouseDownHandler = function(e) {
+ if (Neo.getModifier(e) == 'right') {
+ this.save();
+ } else {
+ this.load();
+ }
+ this.update();
+};
+
+Neo.ReserveControl.prototype.load = function() {
+ Neo.painter.setToolByType(this.reserve.tool)
+ Neo.painter.foregroundColor = this.reserve.color;
+ Neo.painter.lineWidth = this.reserve.size;
+ Neo.painter.alpha = this.reserve.alpha;
+
+ switch (this.reserve.tool) {
+ case Neo.Painter.TOOLTYPE_PEN:
+ case Neo.Painter.TOOLTYPE_BRUSH:
+ case Neo.Painter.TOOLTYPE_TONE:
+ Neo.painter.drawType = this.reserve.drawType;
+ };
+ Neo.updateUI();
+};
+
+Neo.ReserveControl.prototype.save = function() {
+ this.reserve.color = Neo.painter.foregroundColor;
+ this.reserve.size = Neo.painter.lineWidth;
+ this.reserve.drawType = Neo.painter.drawType;
+ this.reserve.alpha = Neo.painter.alpha;
+ this.reserve.tool = Neo.painter.tool.getType();
+ this.element.style.backgroundColor = this.reserve.color;
+ this.update();
+ Neo.updateUI();
+};
+
+Neo.ReserveControl.prototype.update = function() {
+ this.element.style.backgroundColor = this.reserve.color;
+};
+
+/*
+ -------------------------------------------------------------------------
+ ScrollBarButton
+ -------------------------------------------------------------------------
+*/
+
+Neo.scrollH;
+Neo.scrollV;
+
+Neo.ScrollBarButton = function() {};
+Neo.ScrollBarButton.prototype.init = function(name, params) {
+ this.element = document.getElementById(name);
+ this.params = params || {};
+ this.name = name;
+
+ this.element.innerHTML = "<div></div>";
+ this.barButton = this.element.getElementsByTagName("div")[0];
+ this.element['data-bar'] = true;
+ this.barButton['data-bar'] = true;
+
+ if (name == "scrollH") Neo.scrollH = this;
+ if (name == "scrollV") Neo.scrollV = this;
+ return this;
+};
+
+Neo.ScrollBarButton.prototype.update = function(oe) {
+ if (this.name == "scrollH") {
+ var a = oe.destCanvas.width / (oe.canvasWidth * oe.zoom);
+ var barWidth = Math.ceil(oe.destCanvas.width * a);
+ var barX = (oe.scrollBarX) * (oe.destCanvas.width - barWidth);
+ this.barButton.style.width = (Math.ceil(barWidth) - 4) + "px";
+ this.barButton.style.left = Math.floor(barX) + "px";
+
+ } else {
+ var a = oe.destCanvas.height / (oe.canvasHeight * oe.zoom);
+ var barHeight = Math.ceil(oe.destCanvas.height * a);
+ var barY = (oe.scrollBarY) * (oe.destCanvas.height - barHeight);
+ this.barButton.style.height = (Math.ceil(barHeight) - 4) + "px";
+ this.barButton.style.top = Math.floor(barY) + "px";
+ }
+};
+
diff --git a/static/js/palette_selfy.js b/static/js/palette_selfy.js
new file mode 100755
index 0000000..b17134f
--- /dev/null
+++ b/static/js/palette_selfy.js
@@ -0,0 +1,972 @@
+// palette_selfy.js .. for PaintBBS and ShiPainter .. last update : 2004/04/11.
+
+//g .. OJSƂēǂݍłADȏ palette_selfy() Ăяoĉ.
+ var selfv=new Array(); var selfytag=new Array(); //Ȃ.
+
+//ݒ ------------------------------------------------------------
+// selfv[*] ́Aꂼ̐ݒ󔒂ɂƁA̋@\̃{^\Ȃł܂.
+
+// +-l̂Ƃ
+var pnum = 10; // +- ̃ftHgl
+selfv[0] = 'size=3 style="text-align:right">'; // l^O(type=text)̒g
+
+
+// pbgXg.
+// ..evf̒̐F́A1‚Ȃ瑼13F͂̐FɁ2ʂ肩玩擾A
+var psx = 0; // 0:ʓx+x. 1:Fz‚.
+
+// ʓx+xɂƂ̐F. (ݒ肷ꍇ́A11‚̐F \n ŋ؂)
+var pdefs = new Array(
+ '#ffffff',
+ '#ffe6e6','#ffece6','#fff3e6','#fff9e6','#ffffe6',
+ '#f3ffe6','#e6fff3','#e6f3ff','#ffe6ff','#eeddbb',
+''); // 󔒂Ƃ̗vf̓XLbv.
+
+// Fŏz‚Ƃ̐F. (ݒ肷ꍇ́A11‚̐F \n ŋ؂)
+var pdefx = new Array(
+ '#ffffff',
+ '#ffe6e6','#ffcccc','#ff9999','#e6cccc','#e69999',
+ '#cc9999','#cc6666','#996666','#993333','#660000',
+''); // 󔒂Ƃ̗vf̓XLbv.
+
+
+// ftHg̃pbgJ[ (ԍŏɃAvbgɂłF)
+var pbase = '#000000\n#FFFFFF\n#B47575\n#888888\n#FA9696\n#C096C0\n#FFB6FF\n#8080FF\n#25C7C9\n#E7E58D\n#E7962D\n#99CB7B\n#FCECE2\n#F9DDCF';
+
+
+// TvJ[
+ // \pbg̃J[ԍ(̒ɂԍŏo)
+var sams = new Array(0,2,4,6,8,10,12,1,3,5,7,9,11,13); // ʓx+xɂƂ
+var samx = new Array(0,1,2,3,4,5,6,7,8,9,10,11,12,13); // Fŏz‚Ƃ
+
+selfv[1] = '&nbsp;'; // tHg
+selfv[2] = 'style="font-size:xx-small; background-color:$FONT;"';
+ // tHg^O̒g(u$FONTv:16i@RGBFAmɓKp鑮́3)
+ // c color, style="color" style="background", style="background-color")
+
+ // 艺 ">"(‚^O) Ă //
+
+// pbg̑I{^(type=radio)^O̒g
+selfv[3] = 'style="border-width:0;" title="ftHg̃pbg">'; // ftHgF
+selfv[4] = 'style="border-width:0;" title="̃pbggB\n`FbNĂƂɂɉƁA`FbNOA\nFz‚Aʓx+xpbgɁB(1Ԃ̐F{F)">'; // I
+
+
+// {^(type=button)^O̒g
+selfv[5] = 'value="H" title="Fpbg (1Ԃ̐F{F)">'; // F
+selfv[6] = 'value="S" title="ʓxpbg (1Ԃ̐F{F)">'; // ʓx
+selfv[7] = 'value="B" title="xpbg (1Ԃ̐F{F)">\n'; // x
+selfv[8] = 'value="o" title="ɍ̃pbgۑ">'; // Z[u
+selfv[9] = 'value="x" title="̃pbgftHgɖ߂"><br>\n'; // ftHg
+
+selfv[10] = 'value="H+" title="pbgŜ̐F{">'; // F+
+selfv[11] = 'value="H-" title="pbgŜ̐F|">'; // F-
+selfv[12] = 'value="S+" title="pbgŜ̍ʓx{">'; // ʓx+
+selfv[13] = 'value="S-" title="pbgŜ̍ʓx|">'; // ʓx-
+selfv[14] = 'value="B+" title="pbgŜ̖x{">\n'; // x+
+selfv[15] = 'value="B-" title="pbgŜ̖x|">\n'; // x-
+selfv[16] = 'value="RGB+" title="pbgŜRGB{"><br>\n'; // RGB+
+selfv[17] = 'value="RGB-" title="pbgŜRGB|"><br>\n'; // RGB-
+
+
+// Of[V̂Ƃ
+selfv[18] = 'style="border-width:0;" title="2_ɃOf[V (1Ԃ̐F14Ԃ̐F)" checked>2'; // 2_
+selfv[19] = 'style="border-width:0;" title="3_ɃOf[V (1ԁA8ԁA14Ԃ̐F)">3'; // 3_
+selfv[20] = 'style="border-width:0;" title="4_ɃOf[V (1A6A10A14Ԃ̐F)">4<br>\n'; // 4_
+selfv[21] = 'value="RGB" title="RGBŃOf[V">\n'; // RGB?
+selfv[22] = 'value="+HSB" title="+HSBŃOf[V (F{)">\n'; // +HSB
+selfv[23] = 'value="-HSB" title="-HSBŃOf[V (F|)"><br>\n'; // -HSB
+
+
+// ljE폜
+selfv[24] = 'value="+" title="pbglj܂">'; // lj
+selfv[25] = 'value="-" title="I𒆂̃pbg폜܂">\n'; // 폜
+
+
+// Z[uEI[gZ[u
+selfv[26] = 'checked title="Ƀ`FbN‚ĂƁAFύXƂA\n@ŕۑpbgɃpbgZ[u܂B\nۑKp̂́A\n@`FbNĂpbg瑼̃pbgɈړƂA\n@`FbNĂpbgH/S/B{^ƂA\n@2‚̂ƂłBTv̐Fς܂B\nAɃ`FbNĂȂĂA\n@蓮ŃZ[u{^΁Apbgɕۑ܂B">'; // Z[u
+selfv[27] = 'value="O" title="̑Ŝ̃pbgNbL[ɕۑ"><br>\n'; // Z[u
+
+
+// ftHg̃pbg F360ɂ邩Aʓx++x-- ɂ邩
+selfv[28] = 'style="border-width:0;" title="ftHg̃pbǵAFŏz‚">H<sup>o</sup>'; // H
+selfv[29] = 'style="border-width:0;" title="ftHg̃pbǵAʓx{Ax|ŃXg">+S-B'; // +S-B
+selfv[30] = 'value="X" title="Ŝ̃pbgftHgɖ߂"><br>\n'; // ftHg
+
+
+// UPLOAD / DOWNLOAD
+selfv[31] = 'value="" size=8 title="pbgf[^B\nEAbv[hƂ́Aɓ\tĂB\nE_E[hƂ́AɃf[^o͂܂B\n@ [J̃eLXgɂłۑĂB\npbgf[^́A\n pals = new Array(\'#FFFFFF\',\'#B47575\\n#888888\\n...\');\n@̂悤ɁAJS̔z`ŏ܂B">\n'; //
+selfv[32] = 'value="" title="pbgf[^Abv[h">'; //
+selfv[33] = 'value="" title="Ƀpbgf[^_E[h"><br>\n'; //
+
+
+// ̃pbge[u͂łA\[XƂ^OƂ (form^O͏_)
+// tH[n܂
+selfytag[0] = '<table class="ptable"><tr><form name="palepale"><td class="ptd" nowrap>\n<div align=right class="menu">Palette-Selfy</div>\n<div style="font-size:xx-small;">\n';
+
+// tH[̊_1 (•ʂ̃pbg ` Ŝ HSBARGB +- Ƃ)
+selfytag[1] = '<div style="text-align:right; padding:5;">\n';
+
+// tH[̊_2 (Ŝ HSBARGB +- Ƃ ` Of[V)
+selfytag[2] = '</div>\n<div style="text-align:right; padding:0 5 5 5;"">\nGradation';
+
+// tH[̊_3 (Of[V ` pbg̒ljE폜{^)
+selfytag[3] = '</div>\n<div style="text-align:right; padding:0 5 0 5;"">\nPalette';
+
+// tH[̊_4 (pbg̒ljE폜{^ ` Z[u{^)
+selfytag[4] = '\nSave';
+
+// tH[̊_5 (Z[u{^ ` Default H++/+S-B ǂ炩)
+selfytag[5] = '</div>\n<div style="text-align:right; padding:3 5 2 5;"">\nDefault';
+
+// tH[̊_6 (Default H++/+S-B ǂ炩 ` pbg̃Abv/_E[h)
+selfytag[6] = '</div>\n<div style="text-align:right; padding:0 5 0 5;">\nUpdata ';
+
+// tH[I
+selfytag[7] = '</div>\n</div>\n</td></form></tr></table>\n';
+//ݒ肨 ------------------------------------------------------
+
+
+// l (ƂŎgl)
+var d = document;
+var pon,pno; // radio`FbNH / `FbNpbgNO.
+var qon,qno,qmo; // buttonvbVH / vbVpbgNO.
+var pals = new Array(); // color-palette
+var inp = '<input type="button" '; // input-button
+var inr = '<input type="radio" '; // input-button
+var cname = 'selfy='; // cookie-name
+var psx_ch = new Array('',''); // h_sb-checked
+var brwz=0;
+if(d.all){ brwz=1; }else if(d.getElementById){ brwz=2; }
+
+
+// -------------------------------------------------------------------------
+// HSBRGB vZ. l0`255.
+function HSBtoRGB(h,s,v){
+ var r,g,b;
+ if(s==0){
+ r=v; g=v; b=v;
+ }else{
+ var max,min,dif;
+ h*=360/255; //360
+ max=v;
+ dif=v*s/255; //s=(dif/max)*255
+ min=v-dif; //min=max-dif
+
+ if(h<60){
+ r=max; b=min; g=h*dif/60+min;
+ }else if(h<120){
+ g=max; b=min; r=-(h-120)*dif/60+min;
+ }else if(h<180){
+ g=max; r=min; b= (h-120)*dif/60+min;
+ }else if(h<240){
+ b=max; r=min; g=-(h-240)*dif/60+min;
+ }else if(h<300){
+ b=max; g=min; r= (h-240)*dif/60+min;
+ }else if(h<=360){
+ r=max; g=min; b=-(h-360)*dif/60+min;
+ }else{r=0;g=0;b=0;}
+ }
+ return(new Array(r,g,b));
+}
+
+
+// RGBHSB vZ. l0`255.
+function RGBtoHSB(r,g,b){
+ var max,min,dif,h,s,v;
+
+ // max
+ if(r>=g && r>=b){
+ max=r;
+ }else if(g>=b){
+ max=g;
+ }else{
+ max=b;
+ }
+
+ // min
+ if(r<=g && r<=b){
+ min=r;
+ }else if(g<=b){
+ min=g;
+ }else{
+ min=b;
+ }
+
+ // 0,0,0
+ if(max<=0){ return(new Array(0,0,0)); }
+
+ // difference
+ dif=max-min;
+
+ //Hue:
+ if(max>min){
+ if(g==max){
+ h=(b-r)/dif*60+120;
+ }else if(b==max){
+ h=(r-g)/dif*60+240;
+ }else if(b>g){
+ h=(g-b)/dif*60+360;
+ }else{
+ h=(g-b)/dif*60;
+ }
+ if(h<0){
+ h=h+360;
+ }
+ }else{ h=0; }
+ h*=255/360;
+
+ //Saturation:
+ s=(dif/max)*255;
+
+ //Value:
+ v=max;
+
+ return(new Array(h,s,v));
+}
+
+
+// RGB16RGB10 \L. l 000000`ffffff
+function to10rgb(str){
+ var ns = new Array();
+ str = str.replace(/[^0-9a-fA-F]/g,'');
+ for(var i=0; i<=2; i++){
+ ns[i] = str.substr(i*2,2);
+ if(!ns[i]){ ns[i]='00'; }
+ ns[i] = Number(parseInt(ns[i],16).toString(10));
+ }
+ return(ns);
+}
+
+
+// 1016i@
+function format16(n){
+ n = Number(n).toString(16);
+ if(n.length<2){ n='0'+n; }
+ return(n);
+}
+
+
+
+
+// -------------------------------------------------------------------------
+// pbg ( q=1:Avbgpbgɏo͂Ȃ. lst=1:ŏ̂Ƃ
+function rady(p,q,lst){
+ var d = document;
+ var df = d.forms.palepale;
+
+ // ftHgpbg
+ if(!p&&p!=0){ pon=0; pno=''; d.paintbbs.setColors(pbase); return; }
+
+ var ps = pals[p].split('\n');
+ var n = pnum;
+ if(!q && df.num.value){ n = Number(df.num.value); }
+ if(!q && pon==1 && pno!=p){ poncheck(); }
+
+ // ĂȂ炷Ԃ
+ if((pon!=1 || pno!=p) && ps.length==14){
+ if(!q){ pon=1; pno=p; }
+ if(q!=1 && pals[p]){ d.paintbbs.setColors(pals[p]); } return;
+ }
+
+ // checkĂȂ
+ if(pon==1 && pno==p){
+ var pget = String(d.paintbbs.getColors());
+// if(pget==pals[p]){ return; }
+ var cs = pget.split('\n');
+ ps[0] = cs[0]; ps[1] = '';
+ }
+ // ĂȂ
+ var cs = new Array();
+
+ var psy=0; // H/ +S-B
+ psy = check_h_sb(lst);
+
+ if(psy==1){ cs = rh_list(p,n); }// HXg
+ else{ cs = sb_list(p,n); } // +S-B Xg
+
+ if(q){ // ݒ莞
+ pals[p] = String(cs.join('\n'));
+ }
+ if(q!=1){ //
+ if(pon==1 && pno==p){ checkout(); }
+ else{ pon=1; pno=p; }
+// pals[p] = String(cs.join('\n'));
+ d.paintbbs.setColors(String(cs.join('\n')));
+ }
+}
+
+
+// HXg
+function rh_list(p,n){
+ var ps = pals[p].split('\n');
+ var rgb = to10rgb(ps[0]); //RGB
+ var hsv = RGBtoHSB(rgb[0],rgb[1],rgb[2]); //HSB
+ var cs = new Array(ps[0],ps[1]);
+ if(!cs[0]){ cs[0]='#ffffff'; }
+ if(hsv[1]!=0 && !cs[13]){ cs[13]='#ffffff'; }
+
+ for (var i=1; i<13; i++){
+ if(ps[i] && (pon!=1 || pno!=p)){ cs[i]=ps[i]; continue; } //
+ var x,y,z;
+ if(hsv[1]==0){ //
+ x = hsv[0];
+ y = 0;
+ if(i%2==0){ z = 255-i*n; }else{ z = 0+(i-1)*n; }
+ }else if(i>=12){
+ x = hsv[0];
+ y = 0;
+ z = 255-hsv[1];
+ }else{
+ x = hsv[0] + i*255/12;
+ y = hsv[1];
+ z = hsv[2];
+ }
+ while(x<0){ x+=255; } if(y<0){ y=0; } if(z<0){ z=0; } //0
+ while(x>255){ x-=255; } if(y>255){ y=255; } if(z>255){ z=255; } //255
+// for (var j=0; j<=2; j++){ hsv[j] = Math.round(hsv[j]); }
+ rgb = HSBtoRGB(x,y,z);
+ for (var j=0; j<=2; j++){ rgb[j] = Math.round(rgb[j]); }
+ cs[i] = '#'+format16(rgb[0])+format16(rgb[1])+format16(rgb[2]);
+ }
+ return(cs);
+}
+
+
+// +S-B Xg
+function sb_list(p,n){
+ var ps = pals[p].split('\n');
+ var rgb = to10rgb(ps[0]); //RGB
+ var hsv = RGBtoHSB(rgb[0],rgb[1],rgb[2]); //HSB
+ var cs = new Array(ps[0],ps[1]);
+ if(!cs[0]){ cs[0]='#ffffff'; }
+ if(hsv[1]==0 && !cs[1]){ cs[1]='#000000'; }
+ else if(!cs[1]){ cs[1]='#ffffff'; }
+
+ for (var i=2; i<14; i++){
+ if(ps[i] && (pon!=1 || pno!=p)){ cs[i]=ps[i]; continue; } //
+ var y,z;
+ if(hsv[1]==0){ //
+ y = 0;
+ if(i%2==0){ z = 255-i*n; }else{ z = 0+(i-1)*n; }
+ }else{
+ if(i%2==0){ //
+ y = hsv[1]+i*n;
+ z = hsv[2];
+ }else{ //E
+ y = hsv[1]+(i-1)*n;
+ z = hsv[2]-(i-1)*n;
+ }
+ }
+ while(z<0){ z+=255; } while(y<0){ y+=255; } //0
+ while(z>255){ z-=255; } while(y>255){ y-=255; } //255
+// for (var j=0; j<=2; j++){ hsv[j] = Math.round(hsv[j]); }
+ rgb = HSBtoRGB(hsv[0],y,z);
+ for (var j=0; j<=2; j++){ rgb[j] = Math.round(rgb[j]); }
+ cs[i] = '#'+format16(rgb[0])+format16(rgb[1])+format16(rgb[2]);
+ }
+ return(cs);
+}
+
+
+// •ʂH/S/BXgAbv
+function onplus(p,m){
+ var d = document;
+ var df = d.forms.palepale;
+ var n = Number(df.num.value); //+-
+ if(pon==1 && pno==p){ poncheck(); }
+
+ // ÂƂ
+ if(m>0 && n*(qon+1)>38){ qon=0; }
+ if(qno==p && qmo==m && qon>=1){ qon++; n*=(qon+1)/2; }
+ else{ qno=p; qmo=m; qon=1; }
+
+ var ps = pals[p].split('\n');
+ var rgb = to10rgb(ps[0]); //RGB
+ var hsv = RGBtoHSB(rgb[0],rgb[1],rgb[2]); //HSB
+ var cs = new Array();
+ if(m==2){ n*=-1; }
+ for (var i=0; i<14; i++){
+ var z;
+ if(m==0){ z = hsv[m]+((i%2)*2-1)*Math.round(Math.floor(i/2)*(n)); }
+ else{ z = hsv[m]+i*n; }
+ while(z<0){ z+=255; } //0
+ while(z>255){ z-=255; } //255
+// for (var j=0; j<=2; j++){ hsv[j] = Math.round(hsv[j]); }
+ if(m==1){ rgb = HSBtoRGB(hsv[0],z,hsv[2]); } //HSB
+ else if(m==2){ rgb = HSBtoRGB(hsv[0],hsv[1],z); }
+ else{ rgb = HSBtoRGB(z,hsv[1],hsv[2]); } //HSB
+ for (var j=0; j<=2; j++){ rgb[j] = Math.round(rgb[j]); }
+ cs[i] = '#'+format16(rgb[0])+format16(rgb[1])+format16(rgb[2]);
+ }
+ checkout(1);
+ d.paintbbs.setColors(String(cs.join('\n')));
+}
+
+
+// ŜH/S/BvX}CiX
+function alplus(m,n){
+ var d = document;
+ var cs = String(d.paintbbs.getColors()).split('\n');
+ n *= Number(d.forms.palepale.num.value); //+-
+ poncheck();
+
+ for (var i=0; i<cs.length; i++){
+ var rgb = to10rgb(cs[i]); //RGB
+ var hsv = RGBtoHSB(rgb[0],rgb[1],rgb[2]); //HSB
+ //x255̂Ƃʓx
+ if(m==2 && n>0 && hsv[2]>=255){
+ hsv[1] -= n;
+ if(hsv[1]<0){ hsv[1]=0; }else if(hsv[1]>255){ hsv[1]=255; } //0 or 255
+ }
+ hsv[m] += n;
+ //0 255
+ if(m==0){
+ if(hsv[0]<0){ hsv[0]+=255; }else if(hsv[0]>255){ hsv[0]-=255; }
+ }else{
+ if(hsv[m]<0){ hsv[m]=0; }else if(hsv[m]>255){ hsv[m]=255; }
+ }
+// for (var j=0; j<=2; j++){ hsv[j] = Math.round(hsv[j]); }
+ rgb = HSBtoRGB(hsv[0],hsv[1],hsv[2]); //HSB
+ for (var j=0; j<=2; j++){ rgb[j] = Math.round(rgb[j]); }
+ cs[i] = '#'+format16(rgb[0])+format16(rgb[1])+format16(rgb[2]);
+ }
+ checkout();
+ d.paintbbs.setColors(String(cs.join('\n')));
+}
+
+
+// ŜRGBvX}CiX
+function alrgb(n){
+ var d = document;
+ var cs = String(d.paintbbs.getColors()).split('\n');
+ n *= Number(d.forms.palepale.num.value); //+-
+ poncheck();
+
+ for (var i=0; i<cs.length; i++){
+ var rgb = to10rgb(cs[i]); //RGB
+ for (var j=0; j<=2; j++){
+ rgb[j] += n;
+ rgb[j] = Math.round(rgb[j]);
+ if(rgb[j]<0){ rgb[j]=0; } //0
+ if(rgb[j]>255){ rgb[j]=255; } //255
+ }
+ cs[i] = '#'+format16(rgb[0])+format16(rgb[1])+format16(rgb[2]);
+ }
+ checkout();
+ d.paintbbs.setColors(String(cs.join('\n')));
+}
+
+
+// Of[V
+function grady(m){
+ var d = document;
+ var df = d.forms.palepale;
+ var n = 2;
+ if(df.gradc){
+ for(var j=0; j<df.gradc.length; j++){
+ if(df.gradc[j].checked == true){ n = Number(df.gradc[j].value); break; }
+ }
+ }
+ var cs = String(d.paintbbs.getColors()).split('\n');
+ var gs = new Array(1,13);
+ if(n==3){ gs = new Array(1,7,13); }
+ else if(n==4){ gs = new Array(1,5,9,13); }
+ poncheck();
+ cs[1] = cs[0];
+
+ // 2`4F
+ for (var i=0; i<gs.length-1; i++){
+ var p=gs[i]; var q=gs[(i+1)];
+ var rgbp = to10rgb(cs[p]); //RGB
+ var rgbq = to10rgb(cs[q]); //RGB2
+ // HSB
+ var hsvp = new Array();
+ var hsvq = new Array();
+ if(m==1 || m==-1){
+ hsvp = RGBtoHSB(rgbp[0],rgbp[1],rgbp[2]); //HSB
+ hsvq = RGBtoHSB(rgbq[0],rgbq[1],rgbq[2]); //HSB
+ }
+ // pbg̐F
+ for (var k=p+1; k<q; k++){
+ var rgb = new Array();
+ // HSB
+ if(m==1 || m==-1){
+ var hsv = new Array();
+ for (var j=0; j<=2; j++){ // RGB
+ var sa = (hsvp[j]-hsvq[j])/(q-p);
+ if(j==0){ // H
+ if(m*hsvp[j]>m*hsvq[j]){ sa = Math.abs(sa) - 255/(q-p); }
+ hsv[0] = hsvp[0] + m*Math.abs(sa)*(k-p);
+ if(hsv[0]<0){ hsv[0]+=255; }else if(hsv[0]>255){ hsv[0]-=255; }
+ }else{ // S,B
+ hsv[j] = hsvp[j] - sa*(k-p);
+ if(hsv[j]<0){ hsv[j]=0; }else if(hsv[j]>255){ hsv[j]=255; }
+ }
+ }
+ rgb = HSBtoRGB(hsv[0],hsv[1],hsv[2]); //HSB
+ for (var j=0; j<=2; j++){ rgb[j] = Math.round(rgb[j]); }
+ // RGB
+ }else{
+ for (var j=0; j<=2; j++){ // RGB
+ var sa = (rgbp[j]-rgbq[j])/(q-p);
+ rgb[j] = Math.round(rgbp[j] - sa*(k-p));
+ if(rgb[j]<0){ rgb[j]=0; }else if(rgb[j]>255){ rgb[j]=255; } //
+ }
+ }
+ cs[k] = '#'+format16(rgb[0])+format16(rgb[1])+format16(rgb[2]);
+ }
+ }
+ cs[0]=cs[1]; cs[1]='#ffffff';
+ checkout();
+ d.paintbbs.setColors(String(cs.join('\n')));
+}
+
+
+// -------------------------------------------------------------------------
+// pbg̃TvJ[
+function csamp(p,pz,lst){
+ var ss='';
+ var ps = pz.split('\n');
+ var slong = sams.length;
+ var psy = check_h_sb(lst); if(psy==1){ slong = samx.length; }
+ // color-sample
+ for (var i=0; i<slong; i++){
+ // color-title
+ var k,cl='',rgb='',hsv='',ctl='';
+ if(psy==1){ k=samx[i]; }else{ k=sams[i]; }
+ if(ps[k]){
+ rgb = to10rgb(ps[k]); //RGB
+ hsv = RGBtoHSB(rgb[0],rgb[1],rgb[2]); //HSB
+ for (var j=0; j<=2; j++){ hsv[j] = Math.round(hsv[j]); }
+ ctl = 'HSB: '+hsv[0]+','+hsv[1]+','+hsv[2]+'\n';
+ ctl += 'RGB: '+rgb[0]+','+rgb[1]+','+rgb[2]+'\nRGB16: '+ps[k];
+ }
+ if(selfv[2]) cl=selfv[2].replace(/\$FONT/i,ps[k]);
+ if(selfv[1]) ss += '<font id="font_'+p+'_'+k+'" '+cl+' title="'+ctl+'">'+selfv[1]+'</font>';
+ }
+ return ss;
+}
+
+
+// pbg̃Xg
+function palette_list(lst){
+ var d = document;
+ var ds = '';
+ for (var p=0; p<pals.length; p++){
+ if(!pals[p]){ continue; }
+ var samw = csamp(p,pals[p],lst); //Tv
+
+ // element
+ if(selfv[4]) ds+=inr+'name="rad" value="'+p+'" onclick="rady('+p+')" '+selfv[4]+samw+'\n';
+// ds+='<font color="'+ps[0]+'" id="font_'+p+'" title="'+ctl+'">'+samw+'</font>';
+ if(selfv[5]) ds+=inp+'onclick="onplus('+p+',0)" '+selfv[5];
+ if(selfv[6]) ds+=inp+'onclick="onplus('+p+',1)" '+selfv[6];
+ if(selfv[7]) ds+=inp+'onclick="onplus('+p+',2)" '+selfv[7];
+ if(selfv[8]) ds+=inp+'onclick="savy('+p+')" '+selfv[8];
+ if(selfv[9]) ds+=inp+'onclick="defy('+p+')" '+selfv[9];
+ }
+ return ds;
+}
+
+
+// `FbN‚AtHgJ[̃TvύX
+function checkin(p,not){
+ qno=''; qmo=''; qon=0;
+ if(!pals[p]){ return; }
+ var d = document;
+ // font-color
+ var ps = pals[p].split('\n');
+ var slong = sams.length;
+ var psy = check_h_sb(); if(psy==1){ slong = samx.length; }
+ // color-sample
+ for (var i=0; i<slong; i++){
+ // color-title
+ var k,rgb='',hsv='',ctl='';
+ if(psy==1){ k=samx[i]; }else{ k=sams[i]; }
+ if(ps[k]){
+ rgb = to10rgb(ps[k]); //RGB
+ hsv = RGBtoHSB(rgb[0],rgb[1],rgb[2]); //HSB
+ for (var j=0; j<=2; j++){ hsv[j] = Math.round(hsv[j]); }
+ ctl = 'HSB: '+hsv[0]+','+hsv[1]+','+hsv[2]+'\n';
+ ctl += 'RGB: '+rgb[0]+','+rgb[1]+','+rgb[2]+'\nRGB16: '+ps[k];
+ }
+ // replace
+ var ds;
+ if(brwz==1){ ds = d.all('font_'+p+'_'+k); }
+ else if(brwz==2){ ds = d.getElementById('font_'+p+'_'+k); }
+ if(ds){
+ if(ds.style.background){ ds.style.background = ps[k]; }
+ if(ds.style.backgroundColor){ ds.style.backgroundColor = ps[k]; }
+ if(ds.style.color){ ds.style.color = ps[k]; }
+ if(ds.color){ ds.color = ps[k]; }
+ }
+ }
+
+ // check
+ if(not!=1){
+ var df = d.forms.palepale;
+ for(var j=0; j<df.rad.length; j++){
+ if(df.rad[j].value == p){
+ df.rad[j].checked = true; break; }
+ }
+ }
+}
+
+
+// checkO
+function checkout(q){
+ pon=0; pno='';
+ if(q!=1){ qno=''; qmo=''; qon=0; }
+ var df = document.forms.palepale;
+ for(var j=0; j<df.rad.length; j++){
+ if(df.rad[j].checked == true){
+ df.rad[j].checked = false; break; }
+ }
+}
+
+
+// ȑÕpbgۑ
+function poncheck(not){
+ var d = document;
+ var df = document.forms.palepale;
+ if(df.autosave&&df.autosave.checked==false){ return; }
+ else if(pon==1){
+ var pget = String(d.paintbbs.getColors());
+ if(pals[pno] != pget){
+ pals[pno] = pget;
+ checkin(pno,1);
+ if(not!=1){ pcookset(1); }
+ }
+ }
+}
+
+
+// pbgZ[u
+function savy(p){
+ var d = document;
+ pals[p] = String(d.paintbbs.getColors());
+ checkin(p);
+ pcookset(1);
+ pon=1; pno=p;
+}
+
+
+// pbgftHg
+function defy(p){
+ checkout();
+ var q = pdefs[p];
+ var df = document.forms.palepale;
+ if(check_h_sb()==1){ q = pdefx[p]; }
+ if(q){
+ pals[p] = q;
+ rady(p,2);
+ checkin(p);
+ }else{ minsy(p); }
+}
+
+
+// pbglj
+function plusy(){
+ var d = document;
+ if(brwz==1 || brwz==2){
+ var p=pals.length;
+ var pz = String(d.paintbbs.getColors());
+ if(pz){ pals[p] = pz; }
+ else{
+ pals[p] = '#'+Number(d.paintbbs.getInfo().m.iColor).toString(16);
+ rady(p,1);
+ }
+ }
+ if(brwz==1 && d.all('palelist').innerHTML){
+ d.all('palelist').innerHTML = palette_list();
+ checkin(p);
+ }else if(brwz==2 && d.getElementById('palelist').innerHTML){
+ d.getElementById('palelist').innerHTML = palette_list();
+ checkin(p);
+ }
+}
+
+
+// pbg폜
+function minsy(p){
+ var d = document;
+ var df = d.forms.palepale;
+ if(!p&&p!=0){
+ for(var j=0; j<=df.rad.length; j++){
+ if(df.rad[j] && df.rad[j].checked==true){p=Number(df.rad[j].value); break; }
+ }
+ }
+ if((!p&&p!=0)||p<0){ return; }
+ pals[p] = '';
+ var plong = pdefs.length;
+ if(check_h_sb()==1){ plong = pdefx.length; }
+ if(p>=plong){
+ var k=0;
+ var pds = new Array(); pds = pals;
+ pals = new Array();
+ for(var j=0; j<pds.length; j++){
+ if(p!=j && pds[j]){ pals[k] = pds[j]; k++; }
+ }
+ }
+
+ if(brwz==1 && d.all('palelist').innerHTML){
+ d.all('palelist').innerHTML = palette_list();
+ }else if(brwz==2 && d.getElementById('palelist').innerHTML){
+ d.getElementById('palelist').innerHTML = palette_list();
+ }
+ checkout();
+}
+
+
+// pbgftHg
+function def_list(){
+ var okd = confirm("Ŝ̃pbgftHgɖ߂܂B\n낵łH");
+ if(!okd){ return; }
+ var d = document;
+ var df = d.forms.palepale;
+ pals = new Array();
+ var psy = 0;
+ var plong = pdefs.length;
+ if(check_h_sb()==1){ psy=1; plong = pdefx.length; }
+ for (var p=0; p<plong; p++){
+ if(psy==1){ pals[p]=pdefx[p]; }else{ pals[p]=pdefs[p]; }
+ }
+ for (var p=0; p<pals.length; p++){ if(pals[p]){ rady(p,1); } }
+
+ if(brwz==1 && d.all('palelist').innerHTML){
+ d.all('palelist').innerHTML = palette_list();
+ }else if(brwz==2 && d.getElementById('palelist').innerHTML){
+ d.getElementById('palelist').innerHTML = palette_list();
+ }else{
+ for (var p=0; p<pals.length; p++){
+ if(pals[p]){ checkin(p,1); }
+ }
+ }
+}
+
+
+// ftHg h_sb ̃tH[̃`FbN. HɃ`FbN‚ĂȂ1
+function check_h_sb(lst){
+ var ch = 0;
+ var df = document.forms.palepale;
+ if(lst!=1 && df && df.h_sb){
+ for (var i=0; i<df.h_sb.length; i++){
+ if(df.h_sb[i].value==1 && df.h_sb[i].checked==true){ ch=1; break; }
+ }
+ }else{ ch=psx; }
+ return ch;
+}
+
+
+// pbgf[^ Abv[h
+function pupload(){
+ var d = document;
+ var df = d.forms.palepale;
+ var qs = new Array();
+ var palx='';
+ if(df.palz){ palx = df.palz.value; }
+ if(!palx){ return; }
+ pals = new Array();
+ if(eval(palx)){}
+ else{
+ var px = palx.split(/\(|\)/);
+ var ps = px[1].split(',');
+ for (var p=0; p<ps.length; p++){
+ var q=ps[p].replace(/[^0-9a-fA-F]/g,''); pals[p] = q;
+ }
+ }
+
+ for (var p=0; p<pals.length; p++){ if(pals[p]){ rady(p,1); } }
+
+ if(brwz==1 && d.all('palelist').innerHTML){
+ d.all('palelist').innerHTML = palette_list();
+ }else if(brwz==2 && d.getElementById('palelist').innerHTML){
+ d.getElementById('palelist').innerHTML = palette_list();
+ }else{
+ for (var p=0; p<pals.length; p++){
+ if(pals[p]){ checkin(p,1); }
+ }
+ }
+}
+
+
+// pbgf[^ _E[h
+function pdownload(){
+ var d = document;
+ var df = d.forms.palepale;
+ var qs = new Array();
+ for (var p=0; p<pals.length; p++){
+ qs[p] = "\'"+pals[p].replace(/\n/g,'\\n')+"\'";
+ }
+ var palx = 'pals = new Array(\n' + qs.join('\,\n') + '\n);';
+ if(df.palz){ df.palz.value = palx; }
+}
+
+
+// Ŝ̃pbgNbL[ɃZ[u
+function pcookset(o){
+ var df = document.forms.palepale;
+ if(o&&df.autosave&&df.autosave.checked==false){ return; }
+ var exp=new Date();
+ exp.setTime(exp.getTime()+1000*86400*60);
+ var cs = new Array();
+ for(var i=0; i<pals.length; i++){
+ cs[i] = escape(pals[i].replace(/\n/g,'_'));
+ }
+ var cooki = '';
+ if(df.num){ cooki += df.num.value; }
+ cooki += '_'+check_h_sb()+'_%00';
+ cooki += cs.join('%00');
+ document.cookie = cname + cooki + "; expires=" + exp.toGMTString();
+}
+
+
+// Ŝ̃pbgNbL[烍[h
+function pcookget(){
+ var cooks = document.cookie.split("; ");
+ var cooki = '';
+ for (var i=0; i<cooks.length; i++){
+ if (cooks[i].substr(0,cname.length) == cname){
+ cooki = cooks[i].substr(cname.length,cooks[i].length);
+ break;
+ }
+ }
+ if(cooki){
+ var cs = cooki.split('%00');
+ pals = new Array();
+ for(var i=0; i<cs.length-1; i++){
+ pals[i] = unescape(cs[(i+1)]).replace(/\_/g,"\n");
+ }
+ if(cs[0]){
+ var ps = cs[0].split('_');
+ if(ps[0]){ pnum = ps[0]; }
+ if(ps[1]){ psx = ps[1]; }else if(!ps[1]&&ps[1]==0){ psx=0; }
+ }
+ }
+}
+
+
+// 鐔𑝂₵茸炵
+function num_plus(n){
+ var df = document.forms.palepale;
+ var m = Number(df.num.value); var l=n;
+ n *= Math.abs(Math.round(m/10))+1; if(n==0){ n=l; }
+ df.num.value = m+n;
+}
+
+
+// g[ZNg̒l}
+function tone_plus(n){
+ var df = document.forms.palepale;
+ var m = Number(df.tone.value);
+ if(m>0){ n = Math.floor(m/10 + n)*10; }
+ if(n<0){ n=0; }else if(n<5){ n=5; }else if(n>100){ n=100; }
+ df.tone.value = n;
+ tone_sel(n);
+}
+
+
+// g[ZNg
+function tone_sel(t){
+ var dp=document.paintbbs;
+ t = Number(t);
+ if(t==0){ dp.getInfo().m.iTT = 0; }
+ else{ dp.getInfo().m.iTT = Math.floor(t/10)+1; }
+}
+
+
+// -------------------------------------------------------------------------
+// document.write
+function palette_selfy(){
+ var d = document;
+ var df = document.forms.palepale;
+ var pzs=palette_selfy.arguments; //pbgw肪Ƃ
+
+ // browzer
+ if(brwz!=1 && brwz!=2){ return; }
+
+ // pbgƃpbgNbL[
+ var plong = pdefs.length;
+ if(psx==1){ plong = pdefx.length; }
+ for (var p=0; p<plong; p++){
+ if(psx==1){ pals[p]=pdefx[p]; }else{ pals[p]=pdefs[p]; }
+ if(pzs && pzs.length>=1){ var ok=0; //H
+ for (var q=0; q<pzs.length; q++){ if(p==pzs[q]){ ok=1; break; } }
+ if(ok!=1){ pals[p]=''; }
+ }
+ }
+ pcookget(); // cookie-get
+ psx_ch[psx] = 'checked ';
+ for (var p=0; p<pals.length; p++){ if(pals[p]){ rady(p,1,1); } }
+
+ // basic
+ d.write(selfytag[0]);
+ if(selfv[3]) d.write(inr+'name="rad" value="-1" onclick="rady()" '+selfv[3]);
+ if(pbase) d.write(csamp(-1,pbase,1));
+
+ // +-鐔
+ if(selfv[0]){
+ d.write('\n<small>&nbsp;</small>+-');
+ d.write('<input type="text" name="num" value="'+pnum+'" '+selfv[0]);
+ d.write(inp+'value="+" onclick="num_plus(1)">');
+ d.write(inp+'value="-" onclick="num_plus(-1)">\n');
+ }
+ // pbgXg
+ if(pdefs||pdefx) d.write('<div id="palelist">\n'+palette_list(1)+'</div>\n');
+
+ // Ŝ HSBARGB +-
+ if(selfytag[1]) d.write(selfytag[1]);
+ if(selfv[10]) d.write(inp+'onclick="alplus(0,1)" ' +selfv[10]);
+ if(selfv[12]) d.write(inp+'onclick="alplus(1,1)" ' +selfv[12]);
+ if(selfv[14]) d.write(inp+'onclick="alplus(2,1)" ' +selfv[14]);
+ if(selfv[16]) d.write(inp+'onclick="alrgb(1)" ' +selfv[16]);
+ if(selfv[11]) d.write(inp+'onclick="alplus(0,-1)" '+selfv[11]);
+ if(selfv[13]) d.write(inp+'onclick="alplus(1,-1)" '+selfv[13]);
+ if(selfv[15]) d.write(inp+'onclick="alplus(2,-1)" '+selfv[15]);
+ if(selfv[17]) d.write(inp+'onclick="alrgb(-1)" ' +selfv[17]);
+
+ // g[ZNg
+ if(selfv[0]){
+ d.write('Tone <select name="tone" onchange="tone_sel(this.value)">');
+ for (var i=0; i<=100; i+=5){
+ d.write('<option value="'+i+'">'+i+'%</option>\n'); if(i>=10){i+=5;}
+ }
+ d.write('</select>');
+ d.write(inp+'value="+" onclick="tone_plus(1)">');
+ d.write(inp+'value="-" onclick="tone_plus(-1)">\n');
+ }
+
+ // GRADATION
+ if(selfytag[2]) d.write(selfytag[2]);
+ if(selfv[18]) d.write(inr+'name="gradc" value="2" '+selfv[18]); //18
+ if(selfv[19]) d.write(inr+'name="gradc" value="3" '+selfv[19]); //19
+ if(selfv[20]) d.write(inr+'name="gradc" value="4" '+selfv[20]); //20
+ if(selfv[21]) d.write(inp+'onclick="grady(0)" ' +selfv[21]); //21
+ if(selfv[22]) d.write(inp+'onclick="grady(1)" ' +selfv[22]); //22
+ if(selfv[23]) d.write(inp+'onclick="grady(-1)" ' +selfv[23]); //23
+
+ // ljE폜
+ if(selfytag[3]) d.write(selfytag[3]);
+ if(selfv[24]) d.write(inp+'onclick="plusy()" ' +selfv[24]); //24
+ if(selfv[25]) d.write(inp+'onclick="minsy()" ' +selfv[25]); //25
+
+ // Z[uEI[gZ[u
+ if(selfytag[4]) d.write(selfytag[4]);
+ if(selfv[26]) d.write('<input type="checkbox" name="autosave" value="1" '+selfv[26]); //26
+ if(selfv[27]) d.write(inp+'onclick="pcookset()" ' +selfv[27]); //27
+
+ // ftHg
+ if(selfytag[5]) d.write(selfytag[5]);
+ if(selfv[28]) d.write(inr+'name="h_sb" value="1" ' +psx_ch[1]+selfv[28]); //28
+ if(selfv[29]) d.write(inr+'name="h_sb" value="0" ' +psx_ch[0]+selfv[29]); //29
+ if(selfv[30]) d.write(inp+'onclick="def_list()" ' +selfv[30]); //30
+
+ // UPLOAD / DOWNLOAD
+ if(selfytag[6]) d.write(selfytag[6]);
+ if(selfv[31]) d.write('<input type="text" name="palz" '+selfv[31]); //31
+ if(selfv[32]) d.write(inp+'onclick="pupload()" ' +selfv[32]); //32
+ if(selfv[33]) d.write(inp+'onclick="pdownload()" ' +selfv[33]); //33
+
+ // /FORM
+ if(selfytag[7]) d.write(selfytag[7]);
+}
diff --git a/static/js/shobon.js b/static/js/shobon.js
new file mode 100644
index 0000000..b4e48f6
--- /dev/null
+++ b/static/js/shobon.js
@@ -0,0 +1,408 @@
+var are_filters = false;
+var hide_word = new Set()
+var hide_name = new Set();
+var hide_id = new Set();
+
+var shobon_ver = "v0.4+";
+function shobon() {
+ console.log("Running shobon " + shobon_ver);
+
+ boardName = document.getElementsByName("board")[0].value;
+ var inThread = document.getElementsByTagName("body")[0].className == "threadpage";
+ var newRepliesCounter = 0;
+
+ if(!inThread) {
+ /* Create settings link */
+ var box = document.getElementsByClassName("links")[0];
+ box.appendChild(document.createTextNode(" | "));
+ var slnk = document.createElement("a");
+ slnk.href = "#";
+ slnk.innerHTML = "<b>Configuración</b>";
+ slnk.addEventListener("click", shobonSettings);
+ box.appendChild(slnk);
+ }
+
+ if(localStorage.getItem("shobon_on") == "false") {
+ console.log("Shutting down Shobon");
+ return;
+ }
+
+ if (localStorage.getItem("shobon_usefilters") != "false") {
+ loadFilters();
+ }
+
+ var threadList = document.getElementsByClassName("thread");
+ for (var i = 0; i < threadList.length; i++) {
+ var threadId;
+ var thread = threadList[i];
+ var replyList = thread.getElementsByClassName("reply");
+ if (inThread) {
+ threadId = document.getElementsByName("parent")[0].value;
+ } else {
+ threadId = thread.getElementsByTagName("input").parent.value;
+ }
+
+ var lastReplyN = replyList[replyList.length - 1].attributes["data-n"].value;
+
+ if (localStorage.getItem(boardName + "_" + threadId) == null) {
+ localStorage.setItem(boardName + "_" + threadId, lastReplyN);
+ }
+ var lastSeen = localStorage.getItem(boardName + "_" + threadId);
+ var newRepliesInThread = 0;
+
+ for (var e = 0; e < replyList.length; e++) {
+ var reply = replyList[e];
+ var message = reply.getElementsByClassName("msg")[0];
+
+ if(localStorage.getItem("shobon_newposts") == "true") {
+ var replyId = reply.attributes["data-n"].value;
+ var isNewReply = parseInt(lastSeen) < parseInt(replyId);
+
+ if (isNewReply) {
+ newRepliesCounter++;
+ newRepliesInThread++;
+ reply.children[0].innerHTML += " <span class='shobonNew' style='color: #CC6666; font-weight: bold;'>NUEVO!</span>";
+ }
+ }
+
+ // ocultar mensajes que tienen palabras en la blacklist
+ if(are_filters) {
+ checkBlackList(reply);
+ }
+
+ // reemplaza los codigos iso de los paises por el nombre completo
+ if (localStorage.getItem("shobon_country") == "true" && boardName == "world") {
+ replaceCountryName(reply)
+ }
+ // colorea los id's
+ if(localStorage.getItem("shobon_ids") != "false") {
+ paintIds(reply);
+ }
+ // deja la barra superior fija
+ if(localStorage.getItem("shobon_navbar") == "true") {
+ fixedNav();
+ }
+ }
+ if (newRepliesInThread > 0 && !inThread) {
+ thread.getElementsByClassName("threadlinks")[0].innerHTML += "<span onClick='localStorage.setItem(\"" + boardName + "_" + threadId + "\" , " + lastReplyN + "); this.hidden = true;' style='font-weight: bold; background: #81a2be; padding: 5px; border-radius: 5px; float: right; margin-bottom: 10px;'>Marcar como leido</span>";
+ }
+
+ }
+ if (newRepliesCounter > 0 && !inThread) {
+ var banner = document.createElement("span");
+ banner.onclick = function() { this.hidden = true; };
+ banner.setAttribute("style", "font-weight: bold; background: #8c9440; padding: 8px; border-radius: 30px; float: right; position: fixed; bottom: 10px; right: 10px");
+ banner.textContent = "Nuevas respuestas: " + newRepliesCounter;
+ document.body.appendChild(banner);
+ }
+
+ if (inThread) {
+ localStorage.setItem(boardName + "_" + threadId, lastReplyN);
+ }
+
+}
+
+function on_checked(e) {
+ localStorage.setItem(e.target.id, e.target.checked);
+}
+function createCheckbox(name, label, def) {
+ var lbl = document.createElement("label");
+ var chk = document.createElement("input");
+ chk.type = "checkbox";
+ chk.id = name;
+ chk.onchange = on_checked;
+ lbl.appendChild(chk);
+ lbl.insertAdjacentHTML("beforeend", " "+label+" ");
+
+ var checked = localStorage.getItem(name);
+ if(checked !== null) {
+ chk.checked = (checked == "true");
+ } else {
+ chk.checked = def;
+ }
+
+ return lbl;
+}
+function createOption(name, label) {
+ var opt = document.createElement("option");
+ opt.value = name;
+ opt.text = label;
+ return opt;
+}
+function createButton(label, func) {
+ var btn = document.createElement("button");
+ btn.type = "button";
+ btn.textContent = label;
+ btn.onclick = func;
+ return btn;
+}
+function createTh(label, w) {
+ var th = document.createElement("th");
+ th.textContent = label;
+ th.width = w;
+ return th;
+}
+function loadFilters() {
+ var filters = JSON.parse(localStorage.getItem("shobon_filters"));
+
+ if(filters) {
+ are_filters = true;
+ hide_word = new Set(filters.word);
+ hide_name = new Set(filters.name);
+ hide_id = new Set(filters.id);
+ }
+}
+function saveFilters() {
+ var filters = {
+ "word": Array.from(hide_word),
+ "name": Array.from(hide_name),
+ "id": Array.from(hide_id)
+ };
+ localStorage.setItem("shobon_filters", JSON.stringify(filters));
+}
+function deleteFilter(e) {
+ var tr = this.parentElement.parentElement;
+ var name = tr.dataset.name;
+ var type = tr.dataset.type;
+ switch(type) {
+ case "word":
+ hide_word.delete(name);
+ break;
+ case "name":
+ hide_name.delete(name);
+ break;
+ case "id":
+ hide_id.delete(name);
+ break;
+ }
+ saveFilters();
+ tr.remove();
+}
+function addFilter(e) {
+ var name = document.getElementById("txt_filter").value;
+ var type = document.getElementById("lst_type").value;
+ if(!name) {
+ return;
+ }
+
+ switch(type) {
+ case "word":
+ hide_word.add(name);
+ break;
+ case "name":
+ hide_name.add(name);
+ break;
+ case "id":
+ hide_id.add(name);
+ break;
+ }
+ addToFilterTable(name, type);
+ saveFilters();
+ document.getElementById("txt_filter").value = "";
+}
+
+function addToFilterTable(name, type) {
+ var dict = {"word": "Palabra", "name": "Nombre/Tripcode", "id": "ID"};
+ var table = document.getElementById("tbl_filters");
+
+ var td_type = document.createElement("td");
+ td_type.textContent = dict[type];
+ var td_name = document.createElement("td");
+ td_name.textContent = name;
+ var td_btn = document.createElement("td");
+ td_btn.appendChild(createButton("X", deleteFilter));
+
+ var tr = document.createElement("tr");
+ tr.dataset.type = type;
+ tr.dataset.name = name;
+ tr.appendChild(td_type);
+ tr.appendChild(td_name);
+ tr.appendChild(td_btn);
+
+ table.appendChild(tr);
+}
+function shobonSettings(e) {
+ e.preventDefault();
+
+ var titlebox = document.getElementById("titlebox");
+
+ var box = document.getElementById("settings");
+ if(box) {
+ box.hidden = !box.hidden;
+ } else {
+ box = document.createElement("div");
+ box.id = "settings";
+ box.className = "innerbox";
+ box.style.textAlign = "center";
+
+ var p = document.createElement("div");
+ p.appendChild(createCheckbox("shobon_on", "<b>Activar extensión</b>", true));
+ p.appendChild(createCheckbox("shobon_navbar", "Fijar barra superior", false));
+ p.appendChild(createCheckbox("shobon_ids", "Colorear IDs", true));
+ p.appendChild(createCheckbox("shobon_newposts", "Destacar mensajes nuevos", false));
+ p.appendChild(createCheckbox("shobon_country", "Reemplazar códigos de país por nombres", false));
+ p.appendChild(createCheckbox("shobon_time", "Convertir fechas a hora local", true));
+ p.appendChild(createCheckbox("shobon_backlink", "Mostrar quién ha citado un post", true));
+ p.appendChild(createCheckbox("shobon_preview", "Previsualizar citas", true));
+ p.appendChild(createCheckbox("shobon_usefilters", "Activar filtros", false));
+ /*var a = document.createElement("a");
+ a.href = "#";
+ a.innerText = "[Editar filtros]";
+ a.addEventListener("click", function() {
+ var x = document.getElementById("filters");
+ x.hidden = !x.hidden;
+ });
+ p.appendChild(a);*/
+ box.appendChild(p);
+
+ var title2 = document.createElement("h6");
+ title2.textContent = "Filtros";
+ title2.style.fontSize = "18px";
+ title2.style.margin = "0.5em 0";
+ box.appendChild(title2);
+
+ box.appendChild(document.createTextNode("Filtrar mensajes por: "));
+
+ var lst_type = document.createElement("select");
+ lst_type.id = "lst_type";
+ lst_type.appendChild(createOption("word", "Palabra"));
+ lst_type.appendChild(createOption("name", "Nombre/Tripcode"));
+ lst_type.appendChild(createOption("id", "ID"));
+ box.appendChild(lst_type);
+
+ var txt_filter = document.createElement("input");
+ txt_filter.id = "txt_filter";
+ txt_filter.type = "text";
+ box.appendChild(txt_filter);
+
+ box.appendChild(createButton("Agregar", addFilter));
+
+ var tbl_filters = document.createElement("table");
+ tbl_filters.id = "tbl_filters";
+ tbl_filters.border = "1";
+ tbl_filters.style.margin = "0 auto";
+ var row = document.createElement("tr");
+ row.appendChild(createTh("Tipo", 150));
+ row.appendChild(createTh("Filtro", 300));
+ row.appendChild(createTh("", 75));
+ tbl_filters.appendChild(row);
+ box.appendChild(tbl_filters);
+
+ var msg = document.createElement("a");
+ msg.style.display = "block";
+ msg.href = "#";
+ msg.textContent = "Actualizar página para ver cambios";
+ msg.style.marginTop = "1em";
+ msg.addEventListener("click", function() { location.reload(); });
+ box.appendChild(msg);
+
+ titlebox.appendChild(box);
+
+ var i;
+ hide_word.forEach(v => {
+ addToFilterTable(v, "word")
+ });
+ hide_name.forEach(v => {
+ addToFilterTable(v, "name")
+ });
+ hide_id.forEach(v => {
+ addToFilterTable(v, "id")
+ });
+ }
+}
+
+function replaceCountryName(reply) {
+ var country = JSON.parse('{"AF":"Afghanistan","AX":"A£land Islands","AL":"Albania","DZ":"Algeria","AS":"American Samoa","AD":"Andorra","AO":"Angola","AI":"Anguilla","AQ":"Antarctica","AG":"Antigua and Barbuda","AR":"Argentina","AM":"Armenia","AW":"Aruba","AU":"Australia","AT":"Austria","AZ":"Azerbaijan","BS":"Bahamas","BH":"Bahrain","BD":"Bangladesh","BB":"Barbados","BY":"Belarus","BE":"Belgium","BZ":"Belize","BJ":"Benin","BM":"Bermuda","BT":"Bhutan","BO":"Bolivia (Plurinational State of)","BQ":"Bonaire, Sint Eustatius and Saba","BA":"Bosnia and Herzegovina","BW":"Botswana","BV":"Bouvet Island","BR":"Brazil","IO":"British Indian Ocean Territory","BN":"Brunei Darussalam","BG":"Bulgaria","BF":"Burkina Faso","BI":"Burundi","KH":"Cambodia","CM":"Cameroon","CA":"Canada","CV":"Cabo Verde","KY":"Cayman Islands","CF":"Central African Republic","TD":"Chad","CL":"Chile","CN":"China","CX":"Christmas Island","CC":"Cocos (Keeling) Islands","CO":"Colombia","KM":"Comoros","CG":"Congo","CD":"Congo (Democratic Republic of the)","CK":"Cook Islands","CR":"Costa Rica","CI":"CAŒte d\'Ivoire","HR":"Croatia","CU":"Cuba","CW":"CuraAXao","CY":"Cyprus","CZ":"Czech Republic","DK":"Denmark","DJ":"Djibouti","DM":"Dominica","DO":"Dominican Republic","EC":"Ecuador","EG":"Egypt","SV":"El Salvador","GQ":"Equatorial Guinea","ER":"Eritrea","EE":"Estonia","ET":"Ethiopia","FK":"Falkland Islands (Malvinas)","FO":"Faroe Islands","FJ":"Fiji","FI":"Finland","FR":"France","GF":"French Guiana","PF":"French Polynesia","TF":"French Southern Territories","GA":"Gabon","GM":"Gambia","GE":"Georgia","DE":"Germany","GH":"Ghana","GI":"Gibraltar","GR":"Greece","GL":"Greenland","GD":"Grenada","GP":"Guadeloupe","GU":"Guam","GT":"Guatemala","GG":"Guernsey","GN":"Guinea","GW":"Guinea-Bissau","GY":"Guyana","HT":"Haiti","HM":"Heard Island and McDonald Islands","VA":"Holy See","HN":"Honduras","HK":"Hong Kong","HU":"Hungary","IS":"Iceland","IN":"India","ID":"Indonesia","IR":"Iran (Islamic Republic of)","IQ":"Iraq","IE":"Ireland","IM":"Isle of Man","IL":"Israel","IT":"Italy","JM":"Jamaica","JP":"Japan","JE":"Jersey","JO":"Jordan","KZ":"Kazakhstan","KE":"Kenya","KI":"Kiribati","KP":"Korea (Democratic People\'s Republic of)","KR":"Korea (Republic of)","KW":"Kuwait","KG":"Kyrgyzstan","LA":"Lao People\'s Democratic Republic","LV":"Latvia","LB":"Lebanon","LS":"Lesotho","LR":"Liberia","LY":"Libya","LI":"Liechtenstein","LT":"Lithuania","LU":"Luxembourg","MO":"Macao","MK":"Macedonia (the former Yugoslav Republic of)","MG":"Madagascar","MW":"Malawi","MY":"Malaysia","MV":"Maldives","ML":"Mali","MT":"Malta","MH":"Marshall Islands","MQ":"Martinique","MR":"Mauritania","MU":"Mauritius","YT":"Mayotte","MX":"Mexico","FM":"Micronesia (Federated States of)","MD":"Moldova (Republic of)","MC":"Monaco","MN":"Mongolia","ME":"Montenegro","MS":"Montserrat","MA":"Morocco","MZ":"Mozambique","MM":"Myanmar","NA":"Namibia","NR":"Nauru","NP":"Nepal","NL":"Netherlands","NC":"New Caledonia","NZ":"New Zealand","NI":"Nicaragua","NE":"Niger","NG":"Nigeria","NU":"Niue","NF":"Norfolk Island","MP":"Northern Mariana Islands","NO":"Norway","OM":"Oman","PK":"Pakistan","PW":"Palau","PS":"Palestine, State of","PA":"Panama","PG":"Papua New Guinea","PY":"Paraguay","PE":"Peru","PH":"Philippines","PN":"Pitcairn","PL":"Poland","PT":"Portugal","PR":"Puerto Rico","QA":"Qatar","RE":"RAcunion","RO":"Romania","RU":"Russian Federation","RW":"Rwanda","BL":"Saint BarthAclemy","SH":"Saint Helena, Ascension and Tristan da Cunha","KN":"Saint Kitts and Nevis","LC":"Saint Lucia","MF":"Saint Martin (French part)","PM":"Saint Pierre and Miquelon","VC":"Saint Vincent and the Grenadines","WS":"Samoa","SM":"San Marino","ST":"Sao Tome and Principe","SA":"Saudi Arabia","SN":"Senegal","RS":"Serbia","SC":"Seychelles","SL":"Sierra Leone","SG":"Singapore","SX":"Sint Maarten (Dutch part)","SK":"Slovakia","SI":"Slovenia","SB":"Solomon Islands","SO":"Somalia","ZA":"South Africa","GS":"South Georgia and the South Sandwich Islands","SS":"South Sudan","ES":"Spain","LK":"Sri Lanka","SD":"Sudan","SR":"Suriname","SJ":"Svalbard and Jan Mayen","SZ":"Swaziland","SE":"Sweden","CH":"Switzerland","SY":"Syrian Arab Republic","TW":"Taiwan, Province of China","TJ":"Tajikistan","TZ":"Tanzania, United Republic of","TH":"Thailand","TL":"Timor-Leste","TG":"Togo","TK":"Tokelau","TO":"Tonga","TT":"Trinidad and Tobago","TN":"Tunisia","TR":"Turkey","TM":"Turkmenistan","TC":"Turks and Caicos Islands","TV":"Tuvalu","UG":"Uganda","UA":"Ukraine","AE":"United Arab Emirates","GB":"United Kingdom of Great Britain and Northern Ireland","US":"United States of America","UM":"United States Minor Outlying Islands","UY":"Uruguay","UZ":"Uzbekistan","VU":"Vanuatu","VE":"Venezuela (Bolivarian Republic of)","VN":"Viet Nam","VG":"Virgin Islands (British)","VI":"Virgin Islands (U.S.)","WF":"Wallis and Futuna","EH":"Western Sahara","YE":"Yemen","ZM":"Zambia","ZW":"Zimbabwe"}');
+ var countryEM = reply.getElementsByTagName("em")[0];
+ var newCountryStr = country[countryEM.innerText.substr(1, 2)];
+ countryEM.innerText = "(" + newCountryStr + ")";
+}
+
+function checkBlackList(reply) {
+ var i;
+
+ // Check words
+ var low = reply.children[1].innerText.toLowerCase();
+ hide_word.forEach(v => {
+ console.log(v);
+ if (low.includes(v.toLowerCase())) {
+ hidepost(reply);
+ }
+ });
+
+ // Check name/trip
+ var msg_name = reply.firstElementChild.getElementsByClassName("name")[0].textContent.toLowerCase();
+ hide_name.forEach(v => {
+ if (msg_name.includes(hide_name[i])) {
+ hidepost(reply);
+ }
+ });
+
+ // Check ID
+ var date_div = reply.firstElementChild.getElementsByClassName("date")[0].textContent;
+ var id_index = date_div.indexOf("ID:");
+ if(id_index != -1) {
+ var id = date_div.substr(id_index+3);
+
+ hide_id.forEach(v => {
+ if(id.includes(v)) {
+ hidepost(reply);
+ }
+ });
+ }
+}
+
+function paintIds(reply) {
+ var dateId = reply.getElementsByClassName("date")[0];
+ if (dateId.innerText.includes("ID:")) {
+ var postDate = dateId.innerText.split("ID:")[0];
+ var userId = dateId.innerText.split("ID:")[1];
+ var idColor = toHex(userId).substring(0, 6);
+ var reverseColor = invertColor(idColor);
+ var lastChar = userId.substring(userId.length-1, userId.length);
+ dateId.innerHTML = postDate + "<span style='background-color:#" + idColor + "; color:#" + reverseColor + "; padding:0 3px; border-radius:5px; font-size:0.9em; vertical-align:top;'>ID:" + userId + "</span>";
+ }
+}
+
+function toHex(str) {
+ var hex = '';
+ for (var i = 0; i < str.length; i++) {
+ hex += '' + (str.charCodeAt(i) + 125).toString(16);
+ }
+ return hex;
+}
+
+function invertColor(hex) {
+ if (hex.indexOf('#') === 0) {
+ hex = hex.slice(1);
+ }
+ // convert 3-digit hex to 6-digits.
+ if (hex.length === 3) {
+ hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
+ }
+ if (hex.length !== 6) {
+ throw new Error('Invalid HEX color.');
+ }
+ // invert color components
+ var r = (255 - parseInt(hex.slice(0, 2), 16)).toString(16),
+ g = (255 - parseInt(hex.slice(2, 4), 16)).toString(16),
+ b = (255 - parseInt(hex.slice(4, 6), 16)).toString(16);
+ // pad each with zeros and return
+ return padZero(r) + padZero(g) + padZero(b);
+}
+
+function padZero(str, len) {
+ len = len || 2;
+ var zeros = new Array(len).join('0');
+ return (zeros + str).slice(-len);
+}
+
+function fixedNav() {
+ if (document.body.className === "mainpage" || document.body.className === "threads") {
+ document.getElementById("main_nav").style.position = "fixed";
+ document.getElementById("main_nav").style.top = "0";
+ document.body.style.marginTop = "2em";
+ }
+}
+
+document.addEventListener('DOMContentLoaded', shobon, false); \ No newline at end of file
diff --git a/static/js/tegaki/tegaki.css b/static/js/tegaki/tegaki.css
new file mode 100644
index 0000000..d2e3591
--- /dev/null
+++ b/static/js/tegaki/tegaki.css
@@ -0,0 +1,187 @@
+@font-face {
+ font-family: 'tegaki';
+ src: url('data:application/octet-stream;base64,d09GRgABAAAAAAyIAA4AAAAAFVAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABPUy8yAAABRAAAAEQAAABWPeFIsGNtYXAAAAGIAAAAOgAAAUrQFxm3Y3Z0IAAAAcQAAAAKAAAACgAAAABmcGdtAAAB0AAABZQAAAtwiJCQWWdhc3AAAAdkAAAACAAAAAgAAAAQZ2x5ZgAAB2wAAAI+AAAC7u/G5z9oZWFkAAAJrAAAADYAAAA2BIBHAWhoZWEAAAnkAAAAHgAAACQHlwNRaG10eAAACgQAAAAWAAAAIBsOAABsb2NhAAAKHAAAABIAAAASA2cCrm1heHAAAAowAAAAIAAAACAAmwu2bmFtZQAAClAAAAF+AAACte3MYkJwb3N0AAAL0AAAAFAAAABnZ1gGo3ByZXAAAAwgAAAAZQAAAHvdawOFeJxjYGROYpzAwMrAwVTFtIeBgaEHQjM+YDBkZGJgYGJgZWbACgLSXFMYHF4wvGBjDvqfxRDFzM3gDxRmBMkBANw6Cw94nGNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZgYGF6w/f8PUvCCAURLMELVAwEjG8OIBwBqdQa0AAAAAAAAAAAAAAAAAAB4nK1WaXMTRxCd1WHLNj6CDxI2gVnGcox2VpjLCBDG7EoW4BzylexCjl1Ldu6LT/wG/ZpekVSRb/y0vB4d2GAnVVQoSv2m9+1M9+ueXpPQksReWI+k3HwpprY2aWTnSUg3bFqO4kPZ2QspU0z+LoiCaLXUvu04JCISgap1hSWC2PfI0iTjQ48yWrYlvWpSbulJd9kaD+qt+vbT0FGO3QklNZuhQ+uRLanCqBJFMu2RkjYtw9VfSVrh5yvMfNUMJYLoJJLGm2EMj+Rn44xWGa3GdhxFkU2WG0WKRDM8iCKPslpin1wxQUD5oBlSXvk0onyEH5EVe5TTCnHJdprf9yU/6R3OvyTieouyJQf+QHZkB3unK/ki0toK46adbEehivB0fSfEI5uT6p/sUV7TaOB2RaYnzQiWyleQWPkJZfYPyWrhfMqXPBrVkoOcCFovc2Jf8g60HkdMiWsmyILujk6IoO6XnKHYY/q4+OO9XSwXIQTIOJb1jkq4EEYpYbOaJG0EOYiSskWV1HpHTJzyOi3iLWG/Tu3oS2e0Sag7MZ6th46tnKjkeDSp00ymTu2k5tGUBlFKOhM85tcBlB/RJK+2sZrEyqNpbDNjJJFQoIVzaSqIZSeWNAXRPJrRm7thmmvXokWaPFDPPXpPb26Fmzs9p+3AP2v8Z3UqpoO9MJ2eDshKfJp2uUnRun56hn8m8UPWAiqRLTbDlMVDtn4H5eVjS47CawNs957zK+h99kTIpIH4G/AeL9UpBUyFmFVQC9201rUsy9RqVotUZOq7IU0rX9ZpAk05Dn1jX8Y4/q+ZGUtMCd/vxOnZEZeeufYlyDSH3GZdj+Z1arFdgM5sz+k0y/Z9nebYfqDTPNvzOh1ha+t0lO2HOi2w/UinY2wvaEGT7jsEchGBXMAGEoGwdRAI20sIhK1CIGwXEQjbIgJhu4RA2H6MQNguIxC2l7Wsmn4qaRw7E8sARYgDoznuyGVuKldTyaUSrotGpzbkKXKrpKJ4Vv0rA/3ikTesgbVAukTW/IpJrnxUleOPrmh508S5Ao5Vf3tzXJ8TD2W/WPhT8L/amqqkV6x5ZHIVeSPQk+NE1yYVj67p8rmqR9f/i4oOa4F+A6UQC0VZlg2+mZDwUafTUA1c5RAzGzMP1/W6Zc3P4fybGCEL6H78NxQaC9yDTllJWe1gr9XXj2W5twflsCdYkmK+zOtb4YuMzEr7RWYpez7yecAVMCqVYasNXK3gzXsS85DpTfJMELcVZYOkjceZILGBYx4wb76TICRMXbWB2imcsIG8YMwp2O+EQ1RvlOVwe6F9Ho2Uf2tX7MgZFU0Q+G32Rtjrs1DyW6yBhCe/1NdAVSFNxbipgEsj5YZq8GFcrdtGMk6gr6jYDcuyig8fR9x3So5lIPlIEatHRz+tvUKd1Ln9yihu3zv9CIJBaWL+9r6Z4qCUd7WSZVZtA1O3GpVT15rDxasO3c2j7nvH2Sdy1jTddE/c9L6mVbeDg7lZEO3bHJSlTC6o68MOG6jLzaXQ6mVckt52DzAsMKDfoRUb/1f3cfg8V6oKo+NIvZ2oH6PPYgzyDzh/R/UF6OcxTLmGlOd7lxOfbtzD2TJdxV2sn+LfwKy15mbpGnBD0w2Yh6xaHbrKDXynBjo90tyO9BDwse4K8QBgE8Bi8InuWsbzKYDxfMYcH+Bz5jBoMofBFnMYbDNnDWCHOQx2mcNgjzkMvmDOOsCXzGEQModBxBwGT5gTADxlDoOvmMPga+Yw+IY59wG+ZQ6DmDkMEuYw2Nd0ayhzixd0F6htUBXowPQTFvewONRUGbK/44Vhf28Qs38wiKk/aro9pP7EC0P92SCm/mIQU3/VdGdI/Y0Xhvq7QUz9wyCmPtMvxnKZwV9GvkuFA8ouNp/z98T7B8IaQLYAAQAB//8AD3icZZI/bNNAFMbvnYOd3KW1kzhnqUQmdVo7FQWi/LGlMKDSUglRZesAylSKVCkMiB2UShUqE1LGSERCSlmYIFIr5q4MDFUpTN1IB8Rahjq8c9oy4OHzu3dPv+/u3iNAyOg3PaCvyAxRByIGN67Pmjqozi3QpLjVO+BJ8cvXIJAicNsS9EBfMeaNfh9lxZB/499a1/t9/ZmQwc6O/n+hflMWEOn9R0krnBTQeyqB3pA1Va+AohUcN6iheLWqH1RQbkNZWNlKWSjpvBjmRUvkYWjZgAvbamEwxMSezJ4IzGZPLrOynOAHUpQ0/CI6+iWVC7/pc5fpMfvsUUSl7y94Y1CeKNF5h/QFSRGHVAjbK3lXTZ0qyHE9gSjHrVUDVcNiH6qu5qhZ0wYf2ZWyf8XU1Fh+Bh8z8OchZgnl3Wrb6XztOO3VB8cQOw4/G3x53RDGUokb8J03wtPwR3ja4LwBcXAh3uBQ31qoL250OhuL9YWt59vbcB9L1+8lJ2malZaML5nMZre7mXHNdpf2XprRnUc/lV06R0y8M6N45wR214NxT60EjHuqfAjXmM3CNc6b3GZQhCLPJZsc3oSPOYe3mGtyHh5hGgty52+5S5cjri65szgwXgLGUxNIeMSVuPAoPIpwHHo8J6XVZAzmwm+MRXY9Jq1zeN7R2egjvUv3yRRyOUFuBvtipbDx47F0AxyFVEFGfhpeawxaOJKfuMMGkwlmtQZx9aHG6D6Lh3YxczgxcZgSJjxRn2riL3t/mWkAAAABAAAAAQAAO8vwqV8PPPUACwPoAAAAANC+FsgAAAAA0L3smP/9/7ED6AMLAAAACAACAAAAAAAAeJxjYGRgYA76n8UQxfyCgeH/NyAJFEEBHACQkgXuAAB4nGN+wcDALIiEXyAwkzUDAwBBEgQmAAAAAAAAAD4AdgCWAPABHAFIAXcAAAABAAAACAA0AAMAAAAAAAIAAAAQAHMAAAAcC3AAAAAAeJx1kM1Kw0AUhc/U/mArLiy4HjeiiOkPurBuxELrSsFFQVzI2E6T1DRTJlOhr+A7+BC+kM/iSTJIEcwwk++ee+7NnQA4wDcEyueSu2SBOqOSK2jg2vMO9VvPVfKd5xpauPdc53ry3MQZXjy30MYHO4jqLqMFPj0L7ImG5wr2RdvzDvUjz1XyuecaDsWV5zr1B89NTMSz5xaOxdfQrDY2DiMnT4anst/tXcjXjTSU4lQlUq1dZGwmb+TcpE4niQmmZul0qN7iRx2uE2XLoDwn2maxSWUv6JbCWKfaKqdnedfsPew7N5dza5Zy5PvJlTULPXVB5Nxq0OlsfwdDGKywgUWMEBEcJE6onvLdRxc9XJBe6ZB0lq4YKRQSKgprVkRFJmN8wz1nlFLVdCTkAFOey0IJWfHG+seC18wrVm5ntnlCzvvGRUfJWQJOtO0Yk9PCpQp99jtrhne6+lQdJ8qnssUUEqM/80neP88tqEypB8VfcFQH6HD9c58fnU58DwAAeJxjYGKAAC4G7ICDgYGRiZGZkYWRlZGNkZ2Rgy05MS85NYelIKe0mDU3M6+0mDm1MpUzJb88Tze/IDWPvbQATHPlpJal5uiCxBkYAP+wElx4nGPw3sFwIihiIyNjX+QGxp0cDBwMyQUbGVidNjIwaEFoDhR6JwMDAycyi5nBZaMKY0dgxAaHjoiNzCkuG9VAvF0cDQyMLA4dySERICWRQLCRgUdrB+P/1g0svRuZGFwAB9MiuAAAAA==') format('woff');
+ font-weight: normal;
+ font-style: normal;
+}
+
+.tegaki-icon:before {
+ font-size: 10px;
+ width: 10px;
+ font-family: 'tegaki';
+ font-style: normal;
+ font-weight: normal;
+ speak: none;
+ display: inline-block;
+ text-align: center;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1em;
+}
+
+.tegaki-cancel:before { content: '\e800'; } /* '' */
+.tegaki-plus:before { content: '\e801'; } /* '' */
+.tegaki-minus:before { content: '\e802'; } /* '' */
+.tegaki-eye:before { content: '\e803'; } /* '' */
+.tegaki-down-open:before { content: '\e804'; } /* '' */
+.tegaki-up-open:before { content: '\e805'; } /* '' */
+.tegaki-level-down:before { content: '\e806'; } /* '' */
+
+#tegaki {
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ background-color: #a3b1bf;
+ color: #000;
+ font-family: arial, sans-serif;
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ overflow: auto;
+ z-index: 9999;
+ image-rendering: optimizeSpeed;
+ image-rendering: -webkit-optimize-contrast;
+ image-rendering: pixelated;
+ image-rendering: -moz-crisp-edges;
+}
+
+#tegaki-debug {
+ position: absolute;
+ left: 0;
+ top: 0;
+}
+
+#tegaki-debug canvas {
+ width: 75px;
+ height: 75px;
+ display: block;
+ border: 1px solid black;
+}
+
+.tegaki-backdrop {
+ overflow: hidden;
+}
+
+.tegaki-hidden {
+ display: none !important;
+}
+
+.tegaki-strike {
+ text-decoration: line-through;
+}
+
+#tegaki-cnt {
+ left: 50%;
+ top: 50%;
+ position: absolute;
+}
+
+#tegaki-cnt.tegaki-overflow-x {
+ left: 10px;
+ margin-left: 0 !important;
+}
+
+#tegaki-cnt.tegaki-overflow-y {
+ top: 10px;
+ margin-top: 0 !important;
+}
+
+.tegaki-tb-btn {
+ margin-left: 10px;
+ cursor: pointer;
+ text-decoration: none;
+}
+
+.tegaki-tb-btn:hover {
+ color: #007FFF;
+}
+
+.tegaki-tb-btn:focus {
+ color: #007FFF;
+ outline: none;
+}
+
+#tegaki-menu-bar {
+ font-size: 12px;
+ white-space: nowrap;
+ position: absolute;
+ right: 0;
+}
+
+#tegaki-canvas {
+ -moz-box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
+ background: #FFFAFA;
+}
+
+#tegaki-layers {
+ display: inline-block;
+ font-size: 0;
+}
+
+#tegaki-finish-btn {
+ font-weight: bold;
+}
+
+.tegaki-ctrlgrp {
+ margin-bottom: 5px;
+}
+
+.tegaki-label {
+ font-size: 10px;
+}
+
+.tegaki-label:after {
+ content: ' ' attr(data-value);
+}
+
+#tegaki-ghost-layer,
+.tegaki-layer {
+ position: absolute;
+ left: 0;
+}
+
+#tegaki-ctrl {
+ position: absolute;
+ display: inline-block;
+ width: 80px;
+ padding-left: 5px;
+ font-size: 14px;
+}
+
+#tegaki-color {
+ padding: 0;
+ border: 0;
+ display: block;
+ width: 25px;
+ height: 25px;
+ cursor: pointer;
+}
+
+#tegaki-layer-grp span {
+ font-size: 12px;
+ margin-right: 3px;
+ cursor: pointer;
+}
+
+#tegaki-layer-grp span:hover {
+ color: #007FFF;
+}
+
+#tegaki-color::-moz-focus-inner {
+ border: none;
+ padding: 0;
+}
+
+#tegaki-alpha,
+#tegaki-size {
+ width: 90%;
+ margin: auto;
+}
+
+#tegaki-ctrl select {
+ font-size: 11px;
+ width: 100%;
+}
diff --git a/static/js/tegaki/tegaki.js b/static/js/tegaki/tegaki.js
new file mode 100644
index 0000000..3d38d00
--- /dev/null
+++ b/static/js/tegaki/tegaki.js
@@ -0,0 +1,1947 @@
+var TegakiBrush = {
+ brushFn: function(x, y) {
+ var i, ctx, dest, data, len, kernel;
+
+ x = 0 | x;
+ y = 0 | y;
+
+ ctx = Tegaki.ghostCtx;
+ dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
+ data = dest.data;
+ kernel = this.kernel;
+ len = kernel.length;
+
+ i = 0;
+ while (i < len) {
+ data[i] = this.rgb[0]; ++i;
+ data[i] = this.rgb[1]; ++i;
+ data[i] = this.rgb[2]; ++i;
+ data[i] += kernel[i] * (1.0 - data[i] / 255); ++i;
+ }
+
+ ctx.putImageData(dest, x, y);
+ },
+
+ commit: function() {
+ Tegaki.activeCtx.drawImage(Tegaki.ghostCanvas, 0, 0);
+ Tegaki.ghostCtx.clearRect(0, 0,
+ Tegaki.ghostCanvas.width, Tegaki.ghostCanvas.height
+ );
+ },
+
+ draw: function(posX, posY, pt) {
+ var offset, mx, my, fromX, fromY, dx, dy, err, derr, step, stepAcc;
+
+ offset = this.center;
+ step = this.stepSize;
+ stepAcc = this.stepAcc;
+
+ if (pt === true) {
+ this.stepAcc = 0;
+ this.posX = posX;
+ this.posY = posY;
+ this.brushFn(posX - offset, posY - offset);
+ return;
+ }
+
+ fromX = this.posX;
+ fromY = this.posY;
+
+ if (fromX < posX) { dx = posX - fromX; mx = 1; }
+ else { dx = fromX - posX; mx = -1; }
+ if (fromY < posY) { dy = posY - fromY; my = 1; }
+ else { dy = fromY - posY; my = -1; }
+
+ err = (dx > dy ? dx : -dy) / 2;
+
+ dx = -dx;
+
+ while (true) {
+ ++stepAcc;
+ if (stepAcc > step) {
+ this.brushFn(fromX - offset, fromY - offset);
+ stepAcc = 0;
+ }
+ if (fromX === posX && fromY === posY) {
+ break;
+ }
+ derr = err;
+ if (derr > dx) { err -= dy; fromX += mx; }
+ if (derr < dy) { err -= dx; fromY += my; }
+ }
+
+ this.stepAcc = stepAcc;
+ this.posX = posX;
+ this.posY = posY;
+ },
+
+ generateBrush: function() {
+ var i, size, r, brush, ctx, dest, data, len, sqd, sqlen, hs, col, row,
+ ecol, erow, a;
+
+ size = this.size * 2;
+ r = size / 2;
+
+ brush = T$.el('canvas');
+ brush.width = brush.height = size;
+ ctx = brush.getContext('2d');
+ dest = ctx.getImageData(0, 0, size, size);
+ data = dest.data;
+ len = size * size * 4;
+ sqlen = Math.sqrt(r * r);
+ hs = Math.round(r);
+ col = row = -hs;
+
+ i = 0;
+ while (i < len) {
+ if (col >= hs) {
+ col = -hs;
+ ++row;
+ continue;
+ }
+
+ ecol = col;
+ erow = row;
+
+ if (ecol < 0) { ecol = -ecol; }
+ if (erow < 0) { erow = -erow; }
+
+ sqd = Math.sqrt(ecol * ecol + erow * erow);
+
+ if (sqd > sqlen) {
+ a = 0;
+ }
+ else {
+ a = sqd / sqlen;
+ a = (Math.exp(1 - 1 / a) / a);
+ a = 255 - ((0 | (a * 100 + 0.5)) / 100) * 255;
+ }
+
+ if (this.alphaDamp) {
+ a *= this.alpha * this.alphaDamp;
+ }
+ else {
+ a *= this.alpha;
+ }
+
+ data[i + 3] = a;
+
+ i += 4;
+
+ ++col;
+ }
+
+ ctx.putImageData(dest, 0, 0);
+
+ this.center = r;
+ this.brushSize = size;
+ this.brush = brush;
+ this.kernel = data;
+ },
+
+ setSize: function(size, noBrush) {
+ this.size = size;
+ if (!noBrush) this.generateBrush();
+ this.stepSize = Math.floor(this.size * this.step);
+ },
+
+ setAlpha: function(alpha, noBrush) {
+ this.alpha = alpha;
+ if (!noBrush) this.generateBrush();
+ },
+
+ setColor: function(color, noBrush) {
+ this.rgb = Tegaki.hexToRgb(color);
+ if (!noBrush) this.generateBrush();
+ },
+
+ set: function() {
+ this.setAlpha(this.alpha, true);
+ this.setSize(this.size, true);
+ this.setColor(Tegaki.toolColor, true);
+ this.generateBrush();
+ }
+};
+
+var TegakiPen = {
+ init: function() {
+ this.size = 4;
+ this.alpha = 0.5;
+ this.step = 0.1;
+ this.stepAcc = 0;
+ },
+
+ draw: TegakiBrush.draw,
+
+ commit: TegakiBrush.commit,
+
+ brushFn: TegakiBrush.brushFn,
+
+ generateBrush: function() {
+ var size, r, brush, ctx;
+
+ size = this.size;
+ r = size / 2;
+
+ brush = T$.el('canvas');
+ brush.width = brush.height = size;
+ ctx = brush.getContext('2d');
+ ctx.globalAlpha = this.alpha;
+ ctx.beginPath();
+ ctx.arc(r, r, r, 0, Tegaki.TWOPI, false);
+ ctx.fillStyle = '#000000';
+ ctx.fill();
+ ctx.closePath();
+
+ this.center = r;
+ this.brushSize = size;
+ this.brush = brush;
+ this.kernel = ctx.getImageData(0, 0, this.brushSize, this.brushSize).data;
+ },
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiPipette = {
+ size: 1,
+ alpha: 1,
+ noCursor: true,
+
+ draw: function(posX, posY) {
+ var c, ctx;
+
+ if (true) {
+ ctx = Tegaki.flatten().getContext('2d');
+ }
+ else {
+ ctx = Tegaki.activeCtx;
+ }
+
+ c = Tegaki.getColorAt(ctx, posX, posY);
+
+ Tegaki.setToolColor(c);
+ Tegaki.updateUI('color');
+ }
+};
+
+var TegakiAirbrush = {
+ init: function() {
+ this.size = 32;
+ this.alpha = 0.5;
+ this.alphaDamp = 0.2;
+ this.step = 0.25;
+ this.stepAcc = 0;
+ },
+
+ draw: TegakiBrush.draw,
+
+ commit: TegakiBrush.commit,
+
+ brushFn: TegakiBrush.brushFn,
+
+ generateBrush: TegakiBrush.generateBrush,
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiPencil = {
+ init: function() {
+ this.size = 1;
+ this.alpha = 1.0;
+ this.step = 0.25;
+ this.stepAcc = 0;
+ },
+
+ draw: TegakiBrush.draw,
+
+ commit: TegakiBrush.commit,
+
+ brushFn: function(x, y) {
+ var i, ctx, dest, data, len, kernel, a;
+
+ x = 0 | x;
+ y = 0 | y;
+
+ ctx = Tegaki.ghostCtx;
+ dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
+ data = dest.data;
+ kernel = this.kernel;
+ len = kernel.length;
+
+ a = this.alpha * 255;
+
+ i = 0;
+ while (i < len) {
+ data[i] = this.rgb[0]; ++i;
+ data[i] = this.rgb[1]; ++i;
+ data[i] = this.rgb[2]; ++i;
+ if (kernel[i] > 0) {
+ data[i] = a;
+ }
+ ++i;
+ }
+
+ ctx.putImageData(dest, x, y);
+ },
+
+ generateBrush: TegakiPen.generateBrush,
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiEraser = {
+ init: function() {
+ this.size = 8;
+ this.alpha = 1.0;
+ this.step = 0.25;
+ this.stepAcc = 0;
+ },
+
+ draw: TegakiBrush.draw,
+
+ brushFn: function(x, y) {
+ var i, ctx, dest, data, len, kernel;
+
+ x = 0 | x;
+ y = 0 | y;
+
+ ctx = Tegaki.activeCtx;
+ dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
+ data = dest.data;
+ kernel = this.kernel;
+ len = kernel.length;
+
+ for (i = 3; i < len; i += 4) {
+ if (kernel[i] > 0) {
+ data[i] = 0;
+ }
+ }
+
+ ctx.putImageData(dest, x, y);
+ },
+
+ generateBrush: TegakiPen.generateBrush,
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiDodge = {
+ init: function() {
+ this.size = 24;
+ this.alpha = 0.25;
+ this.alphaDamp = 0.05;
+ this.step = 0.25;
+ this.stepAcc = 0;
+ },
+
+ brushFn: function(x, y) {
+ var i, a, aa, ctx, dest, data, len, kernel;
+
+ x = 0 | x;
+ y = 0 | y;
+
+ ctx = Tegaki.activeCtx;
+ dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
+ data = dest.data;
+ kernel = this.kernel;
+ len = kernel.length;
+
+ i = 0;
+ while (i < len) {
+ aa = kernel[i + 3] * 0.3;
+ a = 1 + kernel[i + 3] / 255;
+ data[i] = data[i] * a + aa; ++i;
+ data[i] = data[i] * a + aa; ++i;
+ data[i] = data[i] * a + aa; ++i;
+ ++i;
+ }
+
+ ctx.putImageData(dest, x, y);
+ },
+
+ draw: TegakiBrush.draw,
+
+ generateBrush: TegakiBrush.generateBrush,
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiBurn = {
+ init: TegakiDodge.init,
+
+ brushFn: function(x, y) {
+ var i, a, ctx, dest, data, len, kernel;
+
+ x = 0 | x;
+ y = 0 | y;
+
+ ctx = Tegaki.activeCtx;
+ dest = ctx.getImageData(x, y, this.brushSize, this.brushSize);
+ data = dest.data;
+ kernel = this.kernel;
+ len = kernel.length;
+
+ i = 0;
+ while (i < len) {
+ a = 1 - kernel[i + 3] / 255;
+ data[i] = data[i] * a; ++i;
+ data[i] = data[i] * a; ++i;
+ data[i] = data[i] * a; ++i;
+ ++i;
+ }
+
+ ctx.putImageData(dest, x, y);
+ },
+
+ draw: TegakiBrush.draw,
+
+ generateBrush: TegakiDodge.generateBrush,
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiBlur = {
+ init: TegakiDodge.init,
+
+ brushFn: function(x, y) {
+ var i, j, ctx, src, size, srcData, dest, destData, lim, kernel,
+ sx, sy, r, g, b, a, aa, acc, kx, ky;
+
+ x = 0 | x;
+ y = 0 | y;
+
+ size = this.brushSize;
+ ctx = Tegaki.activeCtx;
+ src = ctx.getImageData(x, y, size, size);
+ srcData = src.data;
+ dest = ctx.createImageData(size, size);
+ destData = dest.data;
+ kernel = this.kernel;
+ lim = size - 1;
+
+ for (sx = 0; sx < size; ++sx) {
+ for (sy = 0; sy < size; ++sy) {
+ r = g = b = a = acc = 0;
+ i = (sy * size + sx) * 4;
+ if (kernel[(sy * size + sx) * 4 + 3] === 0
+ || sx === 0 || sy === 0 || sx === lim || sy === lim) {
+ destData[i] = srcData[i]; ++i;
+ destData[i] = srcData[i]; ++i;
+ destData[i] = srcData[i]; ++i;
+ destData[i] = srcData[i];
+ continue;
+ }
+ for (kx = -1; kx < 2; ++kx) {
+ for (ky = -1; ky < 2; ++ky) {
+ j = ((sy - ky) * size + (sx - kx)) * 4;
+ aa = srcData[j + 3];
+ acc += aa;
+ r += srcData[j] * aa; ++j;
+ g += srcData[j] * aa; ++j;
+ b += srcData[j] * aa; ++j;
+ a += srcData[j];
+ }
+ }
+ destData[i] = r / acc; ++i;
+ destData[i] = g / acc; ++i;
+ destData[i] = b / acc; ++i;
+ destData[i] = a / 9;
+ }
+ }
+
+ ctx.putImageData(dest, x, y);
+ },
+
+ draw: TegakiBrush.draw,
+
+ generateBrush: TegakiDodge.generateBrush,
+
+ setSize: TegakiBrush.setSize,
+
+ setAlpha: TegakiBrush.setAlpha,
+
+ setColor: TegakiBrush.setColor,
+
+ set: TegakiBrush.set
+};
+
+var TegakiHistory = {
+ maxSize: 10,
+
+ undoStack: [],
+ redoStack: [],
+
+ pendingAction: null,
+
+ clear: function() {
+ this.undoStack = [];
+ this.redoStack = [];
+ this.pendingAction = null;
+ },
+
+ push: function(action) {
+ this.undoStack.push(action);
+
+ if (this.undoStack.length > this.maxSize) {
+ this.undoStack.shift();
+ }
+
+ if (this.redoStack.length > 0) {
+ this.redoStack = [];
+ }
+ },
+
+ undo: function() {
+ var action;
+
+ if (!this.undoStack.length) {
+ return;
+ }
+
+ action = this.undoStack.pop();
+ action.undo();
+
+ this.redoStack.push(action);
+ },
+
+ redo: function() {
+ var action;
+
+ if (!this.redoStack.length) {
+ return;
+ }
+
+ action = this.redoStack.pop();
+ action.redo();
+
+ this.undoStack.push(action);
+ }
+};
+
+var TegakiHistoryActions = {
+ Draw: function(layerId) {
+ this.canvasBefore = null;
+ this.canvasAfter = null;
+ this.layerId = layerId;
+ },
+
+ DestroyLayers: function(indices, layers) {
+ this.indices = indices;
+ this.layers = layers;
+ this.canvasBefore = null;
+ this.canvasAfter = null;
+ this.layerId = null;
+ },
+
+ AddLayer: function(layerId) {
+ this.layerId = layerId;
+ },
+
+ MoveLayer: function(layerId, up) {
+ this.layerId = layerId;
+ this.up = up;
+ }
+};
+
+TegakiHistoryActions.Draw.prototype.addCanvasState = function(canvas, type) {
+ if (type) {
+ this.canvasAfter = T$.copyCanvas(canvas);
+ }
+ else {
+ this.canvasBefore = T$.copyCanvas(canvas);
+ }
+};
+
+TegakiHistoryActions.Draw.prototype.exec = function(type) {
+ var i, layer;
+
+ for (i in Tegaki.layers) {
+ layer = Tegaki.layers[i];
+
+ if (layer.id === this.layerId) {
+ layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
+ layer.ctx.drawImage(type ? this.canvasAfter: this.canvasBefore, 0, 0);
+ }
+ }
+};
+
+TegakiHistoryActions.Draw.prototype.undo = function() {
+ this.exec(0);
+};
+
+TegakiHistoryActions.Draw.prototype.redo = function() {
+ this.exec(1);
+};
+
+TegakiHistoryActions.DestroyLayers.prototype.undo = function() {
+ var i, ii, len, layers, idx, layer, frag;
+
+ layers = new Array(len);
+
+ for (i = 0; (idx = this.indices[i]) !== undefined; ++i) {
+ layers[idx] = this.layers[i];
+ }
+
+ i = ii = 0;
+ len = Tegaki.layers.length + this.layers.length;
+ frag = T$.frag();
+
+ while (i < len) {
+ if (!layers[i]) {
+ layer = layers[i] = Tegaki.layers[ii];
+ Tegaki.layersCnt.removeChild(layer.canvas);
+ ++ii;
+ }
+
+ if (this.layerId && layer.id === this.layerId) {
+ layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height);
+ layer.ctx.drawImage(this.canvasBefore, 0, 0);
+ }
+
+ frag.appendChild(layers[i].canvas);
+
+ ++i;
+ }
+
+ Tegaki.layersCnt.insertBefore(frag, Tegaki.canvas.nextElementSibling);
+
+ Tegaki.layers = layers;
+
+ Tegaki.setActiveLayer();
+
+ Tegaki.rebuildLayerCtrl();
+};
+
+TegakiHistoryActions.DestroyLayers.prototype.redo = function() {
+ var i, layer, ids = [];
+
+ for (i = 0; layer = this.layers[i]; ++i) {
+ ids.push(layer.id);
+ }
+
+ if (this.layerId) {
+ ids.push(this.layerId);
+ Tegaki.mergeLayers(ids);
+ }
+ else {
+ Tegaki.deleteLayers(ids);
+ }
+};
+
+TegakiHistoryActions.MoveLayer.prototype.undo = function() {
+ Tegaki.setActiveLayer(this.layerId);
+ Tegaki.moveLayer(this.layerId, !this.up);
+};
+
+TegakiHistoryActions.MoveLayer.prototype.redo = function() {
+ Tegaki.setActiveLayer(this.layerId);
+ Tegaki.moveLayer(this.layerId, this.up);
+};
+
+TegakiHistoryActions.AddLayer.prototype.undo = function() {
+ Tegaki.deleteLayers([this.layerId]);
+ Tegaki.layerIndex--;
+};
+
+TegakiHistoryActions.AddLayer.prototype.redo = function() {
+ Tegaki.addLayer();
+ Tegaki.setActiveLayer();
+};
+
+var T$ = {
+ docEl: document.documentElement,
+
+ id: function(id) {
+ return document.getElementById(id);
+ },
+
+ cls: function(klass, root) {
+ return (root || document).getElementsByClassName(klass);
+ },
+
+ on: function(o, e, h) {
+ o.addEventListener(e, h, false);
+ },
+
+ off: function(o, e, h) {
+ o.removeEventListener(e, h, false);
+ },
+
+ el: function(name) {
+ return document.createElement(name);
+ },
+
+ frag: function() {
+ return document.createDocumentFragment();
+ },
+
+ extend: function(destination, source) {
+ for (var key in source) {
+ destination[key] = source[key];
+ }
+ },
+
+ selectedOptions: function(el) {
+ var i, opt, sel;
+
+ if (el.selectedOptions) {
+ return el.selectedOptions;
+ }
+
+ sel = [];
+
+ for (i = 0; opt = el.options[i]; ++i) {
+ if (opt.selected) {
+ sel.push(opt);
+ }
+ }
+
+ return sel;
+ },
+
+ copyCanvas: function(source) {
+ var canvas = T$.el('canvas');
+ canvas.width = source.width;
+ canvas.height = source.height;
+ canvas.getContext('2d').drawImage(source, 0, 0);
+
+ return canvas;
+ }
+};
+
+var TegakiStrings = {
+ // Messages
+ badDimensions: 'Invalid dimensions.',
+ promptWidth: 'Canvas width in pixels',
+ promptHeight: 'Canvas height in pixels',
+ confirmDelLayers: 'Delete selected layers?',
+ errorMergeOneLayer: 'You need to select at least 2 layers.',
+ confirmMergeLayers: 'Merge selected layers?',
+ errorLoadImage: 'Could not load the image.',
+ noActiveLayer: 'No active layer.',
+ hiddenActiveLayer: 'The active layer is not visible.',
+ confirmCancel: 'Are you sure? Your work will be lost.',
+ confirmChangeCanvas: 'Changing the canvas will clear all layers and history.',
+
+ // UI
+ color: 'Color',
+ size: 'Size',
+ alpha: 'Opacity',
+ layers: 'Layers',
+ addLayer: 'Add layer',
+ delLayers: 'Delete layers',
+ mergeLayers: 'Merge layers',
+ showHideLayer: 'Toggle visibility',
+ moveLayerUp: 'Move up',
+ moveLayerDown: 'Move down',
+ tool: 'Tool',
+ changeCanvas: 'Change canvas',
+ blank: 'Blank',
+ newCanvas: 'New',
+ undo: 'Undo',
+ redo: 'Redo',
+ close: 'Close',
+ finish: 'Finish',
+
+ // Tools
+ pen: 'Pen',
+ pencil: 'Pencil',
+ airbrush: 'Airbrush',
+ pipette: 'Pipette',
+ dodge: 'Dodge',
+ burn: 'Burn',
+ blur: 'Blur',
+ eraser: 'Eraser'
+};
+
+var Tegaki = {
+ VERSION: '0.0.1',
+
+ bg: null,
+ cnt: null,
+ canvas: null,
+ ctx: null,
+ layers: [],
+ layersCnt: null,
+ ghostCanvas: null,
+ ghostCtx: null,
+ activeCtx: null,
+ activeLayer: null,
+ layerIndex: null,
+
+ isPainting: false,
+ isErasing: false,
+ isColorPicking: false,
+
+ offsetX: 0,
+ offsetY: 0,
+
+ TWOPI: 2 * Math.PI,
+
+ tools: {
+ pencil: TegakiPencil,
+ pen: TegakiPen,
+ airbrush: TegakiAirbrush,
+ pipette: TegakiPipette,
+ dodge: TegakiDodge,
+ burn: TegakiBurn,
+ blur: TegakiBlur,
+ eraser: TegakiEraser
+ },
+
+ tool: null,
+ toolColor: '#000000',
+
+ bgColor: '#ffffff',
+ maxSize: 32,
+ maxLayers: 25,
+ baseWidth: null,
+ baseHeight: null,
+
+ onDoneCb: null,
+ onCancelCb: null,
+
+ open: function(opts) {
+ var bg, cnt, el, el2, tool, lbl, btn, ctrl, canvas, grp, self = Tegaki;
+
+ if (self.bg) {
+ self.resume();
+ return;
+ }
+
+ if (opts.bgColor) {
+ self.bgColor = opts.bgColor;
+ }
+
+ self.onDoneCb = opts.onDone;
+ self.onCancelCb = opts.onCancel;
+
+ cnt = T$.el('div');
+ cnt.id = 'tegaki-cnt';
+
+ canvas = T$.el('canvas');
+ canvas.id = 'tegaki-canvas';
+ canvas.width = self.baseWidth = opts.width;
+ canvas.height = self.baseHeight = opts.height;
+
+ el = T$.el('div');
+ el.id = 'tegaki-layers';
+ el.appendChild(canvas);
+ self.layersCnt = el;
+
+ cnt.appendChild(el);
+
+ ctrl = T$.el('div');
+ ctrl.id = 'tegaki-ctrl';
+
+ // Colorpicker
+ grp = T$.el('div');
+ grp.className = 'tegaki-ctrlgrp';
+ el = T$.el('input');
+ el.id = 'tegaki-color';
+ el.value = self.toolColor;
+ try {
+ el.type = 'color';
+ } catch(e) {
+ el.type = 'text';
+ }
+ lbl = T$.el('div');
+ lbl.className = 'tegaki-label';
+ lbl.textContent = TegakiStrings.color;
+ grp.appendChild(lbl);
+ T$.on(el, 'change', self.onColorChange);
+ grp.appendChild(el);
+ ctrl.appendChild(grp);
+
+ // Size control
+ grp = T$.el('div');
+ grp.className = 'tegaki-ctrlgrp';
+ el = T$.el('input');
+ el.id = 'tegaki-size';
+ el.min = 1;
+ el.max = self.maxSize;
+ el.type = 'range';
+ lbl = T$.el('div');
+ lbl.className = 'tegaki-label';
+ lbl.textContent = TegakiStrings.size;
+ grp.appendChild(lbl);
+ T$.on(el, 'change', self.onSizeChange);
+ grp.appendChild(el);
+ ctrl.appendChild(grp);
+
+ // Alpha control
+ grp = T$.el('div');
+ grp.className = 'tegaki-ctrlgrp';
+ el = T$.el('input');
+ el.id = 'tegaki-alpha';
+ el.min = 0;
+ el.max = 1;
+ el.step = 0.01;
+ el.type = 'range';
+ lbl = T$.el('div');
+ lbl.className = 'tegaki-label';
+ lbl.textContent = TegakiStrings.alpha;
+ grp.appendChild(lbl);
+ T$.on(el, 'change', self.onAlphaChange);
+ grp.appendChild(el);
+ ctrl.appendChild(grp);
+
+ // Layer control
+ grp = T$.el('div');
+ grp.className = 'tegaki-ctrlgrp';
+ grp.id = 'tegaki-layer-grp';
+ el = T$.el('select');
+ el.id = 'tegaki-layer';
+ el.multiple = true;
+ el.size = 3;
+ lbl = T$.el('div');
+ lbl.className = 'tegaki-label';
+ lbl.textContent = TegakiStrings.layers;
+ grp.appendChild(lbl);
+ T$.on(el, 'change', self.onLayerChange);
+ grp.appendChild(el);
+ el = T$.el('span');
+ el.title = TegakiStrings.addLayer;
+ el.className = 'tegaki-icon tegaki-plus';
+ T$.on(el, 'click', self.onLayerAdd);
+ grp.appendChild(el);
+ el = T$.el('span');
+ el.title = TegakiStrings.delLayers;
+ el.className = 'tegaki-icon tegaki-minus';
+ T$.on(el, 'click', self.onLayerDelete);
+ grp.appendChild(el);
+ el = T$.el('span');
+ el.id = 'tegaki-layer-visibility';
+ el.title = TegakiStrings.showHideLayer;
+ el.className = 'tegaki-icon tegaki-eye';
+ T$.on(el, 'click', self.onLayerVisibilityChange);
+ grp.appendChild(el);
+ el = T$.el('span');
+ el.id = 'tegaki-layer-merge';
+ el.title = TegakiStrings.mergeLayers;
+ el.className = 'tegaki-icon tegaki-level-down';
+ T$.on(el, 'click', self.onMergeLayers);
+ grp.appendChild(el);
+ el = T$.el('span');
+ el.id = 'tegaki-layer-up';
+ el.title = TegakiStrings.moveLayerUp;
+ el.setAttribute('data-up', '1');
+ el.className = 'tegaki-icon tegaki-up-open';
+ T$.on(el, 'click', self.onMoveLayer);
+ grp.appendChild(el);
+ el = T$.el('span');
+ el.id = 'tegaki-layer-down';
+ el.title = TegakiStrings.moveLayerDown;
+ el.className = 'tegaki-icon tegaki-down-open';
+ T$.on(el, 'click', self.onMoveLayer);
+ grp.appendChild(el);
+ ctrl.appendChild(grp);
+
+ // Tool selector
+ grp = T$.el('div');
+ grp.className = 'tegaki-ctrlgrp';
+ el = T$.el('select');
+ el.id = 'tegaki-tool';
+ for (tool in Tegaki.tools) {
+ el2 = T$.el('option');
+ el2.value = tool;
+ el2.textContent = TegakiStrings[tool];
+ el.appendChild(el2);
+ }
+ lbl = T$.el('div');
+ lbl.className = 'tegaki-label';
+ lbl.textContent = TegakiStrings.tool;
+ grp.appendChild(lbl);
+ T$.on(el, 'change', self.onToolChange);
+ grp.appendChild(el);
+ ctrl.appendChild(grp);
+
+ cnt.appendChild(ctrl);
+
+ el = T$.el('div');
+ el.id = 'tegaki-menu-bar';
+
+ if (opts.canvasOptions) {
+ btn = T$.el('select');
+ btn.id = 'tegaki-canvas-select';
+ btn.title = TegakiStrings.changeCanvas;
+ btn.innerHTML = '<option value="0">' + TegakiStrings.blank + '</option>';
+ opts.canvasOptions(btn);
+ T$.on(btn, 'change', Tegaki.onCanvasSelected);
+ T$.on(btn, 'focus', Tegaki.onCanvasSelectFocused);
+ el.appendChild(btn);
+ }
+
+ btn = T$.el('span');
+ btn.className = 'tegaki-tb-btn';
+ btn.textContent = TegakiStrings.newCanvas;
+ T$.on(btn, 'click', Tegaki.onNewClick);
+ el.appendChild(btn);
+
+ btn = T$.el('span');
+ btn.className = 'tegaki-tb-btn';
+ btn.textContent = TegakiStrings.undo;
+ T$.on(btn, 'click', Tegaki.onUndoClick);
+ el.appendChild(btn);
+
+ btn = T$.el('span');
+ btn.className = 'tegaki-tb-btn';
+ btn.textContent = TegakiStrings.redo;
+ T$.on(btn, 'click', Tegaki.onRedoClick);
+ el.appendChild(btn);
+
+ btn = T$.el('span');
+ btn.className = 'tegaki-tb-btn';
+ btn.textContent = TegakiStrings.close;
+ T$.on(btn, 'click', Tegaki.onCancelClick);
+ el.appendChild(btn);
+
+ btn = T$.el('span');
+ btn.id = 'tegaki-finish-btn';
+ btn.className = 'tegaki-tb-btn';
+ btn.textContent = TegakiStrings.finish;
+ T$.on(btn, 'click', Tegaki.onDoneClick);
+ el.appendChild(btn);
+
+ cnt.appendChild(el);
+
+ bg = T$.el('div');
+ bg.id = 'tegaki';
+ self.bg = bg;
+ bg.appendChild(cnt);
+ document.body.appendChild(bg);
+ document.body.classList.add('tegaki-backdrop');
+
+ el = T$.el('canvas');
+ el.id = 'tegaki-ghost-layer';
+ el.width = canvas.width;
+ el.height = canvas.height;
+ self.ghostCanvas = el;
+ self.ghostCtx = el.getContext('2d');
+
+ self.cnt = cnt;
+ self.centerCnt();
+
+ self.canvas = canvas;
+
+ self.ctx = canvas.getContext('2d');
+ self.ctx.fillStyle = self.bgColor;
+ self.ctx.fillRect(0, 0, opts.width, opts.height);
+
+ self.addLayer();
+
+ self.setActiveLayer();
+
+ self.initTools();
+
+ self.setTool('pencil');
+
+ self.updateUI();
+
+ self.updateCursor();
+ self.updatePosOffset();
+
+ T$.on(self.bg, 'mousemove', self.onMouseMove);
+ T$.on(self.bg, 'mousedown', self.onMouseDown);
+ T$.on(self.layersCnt, 'contextmenu', self.onDummy);
+
+ T$.on(document, 'mouseup', self.onMouseUp);
+ T$.on(window, 'resize', self.updatePosOffset);
+ T$.on(window, 'scroll', self.updatePosOffset);
+ },
+
+ initTools: function() {
+ var tool;
+
+ for (tool in Tegaki.tools) {
+ (tool = Tegaki.tools[tool]) && tool.init && tool.init();
+ }
+ },
+
+ hexToRgb: function(hex) {
+ var c = hex.match(/^#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})$/i);
+
+ if (c) {
+ return [
+ parseInt(c[1], 16),
+ parseInt(c[2], 16),
+ parseInt(c[3], 16)
+ ];
+ }
+
+ return null;
+ },
+
+ centerCnt: function() {
+ var aabb, cnt;
+
+ cnt = Tegaki.cnt;
+ aabb = cnt.getBoundingClientRect();
+
+ if (aabb.width > T$.docEl.clientWidth || aabb.height > T$.docEl.clientHeight) {
+ if (aabb.width > T$.docEl.clientWidth) {
+ cnt.classList.add('tegaki-overflow-x');
+ }
+ if (aabb.height > T$.docEl.clientHeight) {
+ cnt.classList.add('tegaki-overflow-y');
+ }
+ }
+ else {
+ cnt.classList.remove('tegaki-overflow-x');
+ cnt.classList.remove('tegaki-overflow-y');
+ }
+
+ cnt.style.marginTop = -Math.round(aabb.height / 2) + 'px';
+ cnt.style.marginLeft = -Math.round(aabb.width / 2) + 'px';
+ },
+
+ getCursorPos: function(e, axis) {
+ if (axis === 0) {
+ return e.clientX + window.pageXOffset + Tegaki.bg.scrollLeft - Tegaki.offsetX;
+ }
+ else {
+ return e.clientY + window.pageYOffset + Tegaki.bg.scrollTop - Tegaki.offsetY;
+ }
+ },
+
+ resume: function() {
+ Tegaki.bg.classList.remove('tegaki-hidden');
+ document.body.classList.add('tegaki-backdrop');
+
+ Tegaki.centerCnt();
+ Tegaki.updatePosOffset();
+
+ T$.on(document, 'mouseup', Tegaki.onMouseUp);
+ T$.on(window, 'resize', Tegaki.updatePosOffset);
+ T$.on(window, 'scroll', Tegaki.updatePosOffset);
+ },
+
+ hide: function() {
+ Tegaki.bg.classList.add('tegaki-hidden');
+ document.body.classList.remove('tegaki-backdrop');
+
+ T$.off(document, 'mouseup', Tegaki.onMouseUp);
+ T$.off(window, 'resize', Tegaki.updatePosOffset);
+ T$.off(window, 'scroll', Tegaki.updatePosOffset);
+ },
+
+ destroy: function() {
+ T$.off(Tegaki.bg, 'mousemove', Tegaki.onMouseMove);
+ T$.off(Tegaki.bg, 'mousedown', Tegaki.onMouseDown);
+ T$.off(Tegaki.layersCnt, 'contextmenu', Tegaki.onDummy);
+
+ T$.off(document, 'mouseup', Tegaki.onMouseUp);
+ T$.off(window, 'resize', Tegaki.updatePosOffset);
+ T$.off(window, 'scroll', Tegaki.updatePosOffset);
+
+ Tegaki.bg.parentNode.removeChild(Tegaki.bg);
+
+ TegakiHistory.clear();
+
+ document.body.classList.remove('tegaki-backdrop');
+
+ Tegaki.bg = null;
+ Tegaki.cnt = null;
+ Tegaki.canvas = null;
+ Tegaki.ctx = null;
+ Tegaki.layers = [];
+ Tegaki.layerIndex = 0;
+ Tegaki.activeCtx = null;
+ },
+
+ flatten: function() {
+ var i, layer, canvas, ctx;
+
+ canvas = T$.el('canvas');
+ canvas.width = Tegaki.canvas.width;
+ canvas.height = Tegaki.canvas.height;
+
+ ctx = canvas.getContext('2d');
+
+ ctx.drawImage(Tegaki.canvas, 0, 0);
+
+ for (i = 0; layer = Tegaki.layers[i]; ++i) {
+ if (layer.canvas.classList.contains('tegaki-hidden')) {
+ continue;
+ }
+ ctx.drawImage(layer.canvas, 0, 0);
+ }
+
+ return canvas;
+ },
+
+ updateUI: function(type) {
+ var i, ary, el, tool = Tegaki.tool;
+
+ ary = type ? [type] : ['size', 'alpha', 'color'];
+
+ for (i = 0; type = ary[i]; ++i) {
+ el = T$.id('tegaki-' + type);
+ el.value = type === 'color' ? Tegaki.toolColor : tool[type];
+
+ if (el.type === 'range') {
+ el.previousElementSibling.setAttribute('data-value', tool[type]);
+ }
+ }
+ },
+
+ rebuildLayerCtrl: function() {
+ var i, layer, sel, opt;
+
+ sel = T$.id('tegaki-layer');
+
+ sel.textContent = '';
+
+ for (i = Tegaki.layers.length - 1; layer = Tegaki.layers[i]; i--) {
+ opt = T$.el('option');
+ opt.value = layer.id;
+ opt.textContent = layer.name;
+ sel.appendChild(opt);
+ }
+ },
+
+ getColorAt: function(ctx, posX, posY) {
+ var rgba = ctx.getImageData(posX, posY, 1, 1).data;
+
+ return '#'
+ + ('0' + rgba[0].toString(16)).slice(-2)
+ + ('0' + rgba[1].toString(16)).slice(-2)
+ + ('0' + rgba[2].toString(16)).slice(-2);
+ },
+
+ renderCircle: function(r) {
+ var i, canvas, ctx, d, e, x, y, dx, dy, idata, data, c, color;
+
+ e = 1 - r;
+ dx = 0;
+ dy = -2 * r;
+ x = 0;
+ y = r;
+ d = 33;
+ c = 16;
+
+ canvas = T$.el('canvas');
+ canvas.width = canvas.height = d;
+ ctx = canvas.getContext('2d');
+ idata = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
+ data = idata.data;
+
+ color = 255;
+
+ data[(c + (c + r) * d) * 4 + 3] = color;
+ data[(c + (c - r) * d) * 4 + 3] = color;
+ data[(c + r + c * d) * 4 + 3] = color;
+ data[(c - r + c * d) * 4 + 3] = color;
+
+ while (x < y) {
+ if (e >= 0) {
+ y--;
+ dy += 2;
+ e += dy;
+ }
+
+ ++x;
+ dx += 2;
+ e += dx;
+
+ data[(c + x + (c + y) * d) * 4 + 3] = color;
+ data[(c - x + (c + y) * d) * 4 + 3] = color;
+ data[(c + x + (c - y) * d) * 4 + 3] = color;
+ data[(c - x + (c - y) * d) * 4 + 3] = color;
+ data[(c + y + (c + x) * d) * 4 + 3] = color;
+ data[(c - y + (c + x) * d) * 4 + 3] = color;
+ data[(c + y + (c - x) * d) * 4 + 3] = color;
+ data[(c - y + (c - x) * d) * 4 + 3] = color;
+ }
+
+ if (r > 0) {
+ for (i = 0; i < 3; ++i) {
+ data[(c + c * d) * 4 + i] = 127;
+ }
+ data[(c + c * d) * 4 + i] = color;
+ }
+
+ ctx.putImageData(idata, 0, 0);
+
+ return canvas;
+ },
+
+ setToolSize: function(size) {
+ Tegaki.tool.setSize && Tegaki.tool.setSize(size);
+ Tegaki.updateCursor();
+ },
+
+ setToolAlpha: function(alpha) {
+ Tegaki.tool.setAlpha && Tegaki.tool.setAlpha(alpha);
+ },
+
+ setToolColor: function(color) {
+ Tegaki.toolColor = color;
+ Tegaki.tool.setColor && Tegaki.tool.setColor(color);
+ Tegaki.updateCursor();
+ },
+
+ setTool: function(tool) {
+ tool = Tegaki.tools[tool];
+ Tegaki.tool = tool;
+ tool.set && tool.set();
+ },
+
+ debugDumpPixelData: function(canvas) {
+ var i, idata, data, len, out, el;
+
+ idata = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height);
+ data = idata.data;
+ len = data.length;
+
+ out = '';
+
+ for (i = 0; i < len; i += 4) {
+ out += data[i] + ' ' + data[i+1] + ' ' + data[i+2] + ' ' + data[i+3] + '%0a';
+ }
+
+ el = document.createElement('a');
+ el.href = 'data:,' + out;
+ el.download = 'dump.txt';
+ document.body.appendChild(el);
+ el.click();
+ document.body.removeChild(el);
+ },
+
+ debugDrawColors: function(sat) {
+ var i, ctx, grad, a;
+
+ Tegaki.resizeCanvas(360, 360);
+
+ ctx = Tegaki.activeCtx;
+ a = ctx.globalAlpha;
+ ctx.globalAlpha = 1;
+
+ ctx.fillStyle = '#000000';
+ ctx.fillRect(0, 0, 360, 360);
+
+ for (i = 0; i < 360; ++i) {
+ if (sat) {
+ grad = ctx.createLinearGradient(0, 0, 10, 360);
+ grad.addColorStop(0, 'hsl(' + i + ', 0%, ' + '50%)');
+ grad.addColorStop(1, 'hsl(' + i + ', 100%, ' + '50%)');
+ ctx.strokeStyle = grad;
+ }
+ else {
+ ctx.strokeStyle = 'hsl(' + i + ', 100%, ' + '50%)';
+ }
+ ctx.beginPath();
+ ctx.moveTo(i, 0);
+ ctx.lineTo(i, 360);
+ ctx.stroke();
+ ctx.closePath();
+ }
+
+ if (!sat) {
+ grad = ctx.createLinearGradient(0, 0, 10, 360);
+ grad.addColorStop(0, '#000000');
+ grad.addColorStop(1, 'rgba(0,0,0,0)');
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, 360, 360);
+ }
+
+ ctx.globalAlpha = a;
+ },
+
+ onNewClick: function() {
+ var width, height, tmp;
+
+ width = prompt(TegakiStrings.promptWidth, Tegaki.canvas.width);
+ if (!width) { return; }
+
+ height = prompt(TegakiStrings.promptHeight, Tegaki.canvas.height);
+ if (!height) { return; }
+
+ width = +width;
+ height = +height;
+
+ if (width < 1 || height < 1) {
+ alert(TegakiStrings.badDimensions);
+ return;
+ }
+
+ tmp = {};
+ Tegaki.copyContextState(Tegaki.activeCtx, tmp);
+ Tegaki.resizeCanvas(width, height);
+ Tegaki.copyContextState(tmp, Tegaki.activeCtx);
+
+ TegakiHistory.clear();
+ Tegaki.centerCnt();
+ Tegaki.updatePosOffset();
+ },
+
+ onUndoClick: function() {
+ TegakiHistory.undo();
+ },
+
+ onRedoClick: function() {
+ TegakiHistory.redo();
+ },
+
+ onDoneClick: function() {
+ Tegaki.hide();
+ Tegaki.onDoneCb();
+ },
+
+ onCancelClick: function() {
+ if (!confirm(TegakiStrings.confirmCancel)) {
+ return;
+ }
+
+ Tegaki.destroy();
+ Tegaki.onCancelCb();
+ },
+
+ onColorChange: function() {
+ Tegaki.setToolColor(this.value);
+ },
+
+ onSizeChange: function() {
+ this.previousElementSibling.setAttribute('data-value', this.value);
+ Tegaki.setToolSize(+this.value);
+ },
+
+ onAlphaChange: function() {
+ this.previousElementSibling.setAttribute('data-value', this.value);
+ Tegaki.setToolAlpha(+this.value);
+ },
+
+ onLayerChange: function() {
+ var selectedOptions = T$.selectedOptions(this);
+
+ if (selectedOptions.length > 1) {
+ Tegaki.activeLayer = null;
+ }
+ else {
+ Tegaki.setActiveLayer(+this.value);
+ }
+ },
+
+ onLayerAdd: function() {
+ TegakiHistory.push(Tegaki.addLayer());
+ Tegaki.setActiveLayer();
+ },
+
+ onLayerDelete: function() {
+ var i, ary, sel, opt, selectedOptions, action;
+
+ sel = T$.id('tegaki-layer');
+
+ selectedOptions = T$.selectedOptions(sel);
+
+ if (Tegaki.layers.length === selectedOptions.length) {
+ return;
+ }
+
+ if (!confirm(TegakiStrings.confirmDelLayers)) {
+ return;
+ }
+
+ if (selectedOptions.length > 1) {
+ ary = [];
+
+ for (i = 0; opt = selectedOptions[i]; ++i) {
+ ary.push(+opt.value);
+ }
+ }
+ else {
+ ary = [+sel.value];
+ }
+
+ action = Tegaki.deleteLayers(ary);
+
+ TegakiHistory.push(action);
+ },
+
+ onLayerVisibilityChange: function() {
+ var i, ary, sel, opt, flag, selectedOptions;
+
+ sel = T$.id('tegaki-layer');
+
+ selectedOptions = T$.selectedOptions(sel);
+
+ if (selectedOptions.length > 1) {
+ ary = [];
+
+ for (i = 0; opt = selectedOptions[i]; ++i) {
+ ary.push(+opt.value);
+ }
+ }
+ else {
+ ary = [+sel.value];
+ }
+
+ flag = !Tegaki.getLayerById(ary[0]).visible;
+
+ Tegaki.setLayerVisibility(ary, flag);
+ },
+
+ onMergeLayers: function() {
+ var i, ary, sel, opt, selectedOptions, action;
+
+ sel = T$.id('tegaki-layer');
+
+ selectedOptions = T$.selectedOptions(sel);
+
+ if (selectedOptions.length > 1) {
+ ary = [];
+
+ for (i = 0; opt = selectedOptions[i]; ++i) {
+ ary.push(+opt.value);
+ }
+ }
+ else {
+ ary = [+sel.value];
+ }
+
+ if (ary.length < 2) {
+ alert(TegakiStrings.errorMergeOneLayer);
+ return;
+ }
+
+ if (!confirm(TegakiStrings.confirmMergeLayers)) {
+ return;
+ }
+
+ action = Tegaki.mergeLayers(ary);
+
+ TegakiHistory.push(action);
+ },
+
+ onMoveLayer: function(e) {
+ var id, action, sel;
+
+ sel = T$.id('tegaki-layer');
+
+ id = +sel.options[sel.selectedIndex].value;
+
+ if (action = Tegaki.moveLayer(id, e.target.hasAttribute('data-up'))) {
+ TegakiHistory.push(action);
+ }
+ },
+
+ onToolChange: function() {
+ Tegaki.setTool(this.value);
+ Tegaki.updateUI();
+ Tegaki.updateCursor();
+ },
+
+ onCanvasSelected: function() {
+ var img;
+
+ if (!confirm(TegakiStrings.confirmChangeCanvas)) {
+ this.selectedIndex = +this.getAttribute('data-current');
+ return;
+ }
+
+ if (this.value === '0') {
+ Tegaki.ctx.fillStyle = Tegaki.bgColor;
+ Tegaki.ctx.fillRect(0, 0, Tegaki.baseWidth, Tegaki.baseHeight);
+ }
+ else {
+ img = T$.el('img');
+ img.onload = Tegaki.onImageLoaded;
+ img.onerror = Tegaki.onImageError;
+ this.disabled = true;
+ img.src = this.value;
+ }
+ },
+
+ onImageLoaded: function() {
+ var el, tmp = {};
+
+ el = T$.id('tegaki-canvas-select');
+ el.setAttribute('data-current', el.selectedIndex);
+ el.disabled = false;
+
+ Tegaki.copyContextState(Tegaki.activeCtx, tmp);
+ Tegaki.resizeCanvas(this.naturalWidth, this.naturalHeight);
+ Tegaki.activeCtx.drawImage(this, 0, 0);
+ Tegaki.copyContextState(tmp, Tegaki.activeCtx);
+
+ TegakiHistory.clear();
+ Tegaki.centerCnt();
+ Tegaki.updatePosOffset();
+ },
+
+ onImageError: function() {
+ var el;
+
+ el = T$.id('tegaki-canvas-select');
+ el.selectedIndex = +el.getAttribute('data-current');
+ el.disabled = false;
+
+ alert(TegakiStrings.errorLoadImage);
+ },
+
+ resizeCanvas: function(width, height) {
+ var i, layer;
+
+ Tegaki.canvas.width = width;
+ Tegaki.canvas.height = height;
+ Tegaki.ghostCanvas.width = width;
+ Tegaki.ghostCanvas.height = height;
+
+ Tegaki.ctx.fillStyle = Tegaki.bgColor;
+ Tegaki.ctx.fillRect(0, 0, width, height);
+
+ for (i = 0; layer = Tegaki.layers[i]; ++i) {
+ Tegaki.layersCnt.removeChild(layer.canvas);
+ }
+
+ Tegaki.activeCtx = null;
+ Tegaki.layers = [];
+ Tegaki.layerIndex = 0;
+ T$.id('tegaki-layer').textContent = '';
+
+ Tegaki.addLayer();
+ Tegaki.setActiveLayer();
+ },
+
+ getLayerIndex: function(id) {
+ var i, layer, layers = Tegaki.layers;
+
+ for (i = 0; layer = layers[i]; ++i) {
+ if (layer.id === id) {
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ getLayerById: function(id) {
+ return Tegaki.layers[Tegaki.getLayerIndex(id)];
+ },
+
+ addLayer: function() {
+ var id, cnt, opt, canvas, layer, nodes, last;
+
+ canvas = T$.el('canvas');
+ canvas.className = 'tegaki-layer';
+ canvas.width = Tegaki.canvas.width;
+ canvas.height = Tegaki.canvas.height;
+
+ id = ++Tegaki.layerIndex;
+
+ layer = {
+ id: id,
+ name: 'Layer ' + id,
+ canvas: canvas,
+ ctx: canvas.getContext('2d'),
+ visible: true,
+ empty: true,
+ opacity: 1.0
+ };
+
+ Tegaki.layers.push(layer);
+
+ cnt = T$.id('tegaki-layer');
+ opt = T$.el('option');
+ opt.value = layer.id;
+ opt.textContent = layer.name;
+ cnt.insertBefore(opt, cnt.firstElementChild);
+
+ nodes = T$.cls('tegaki-layer', Tegaki.layersCnt);
+
+ if (nodes.length) {
+ last = nodes[nodes.length - 1];
+ }
+ else {
+ last = Tegaki.canvas;
+ }
+
+ Tegaki.layersCnt.insertBefore(canvas, last.nextElementSibling);
+
+ return new TegakiHistoryActions.AddLayer(id);
+ },
+
+ deleteLayers: function(ids) {
+ var i, id, len, sel, idx, indices, layers;
+
+ sel = T$.id('tegaki-layer');
+
+ indices = [];
+ layers = [];
+
+ for (i = 0, len = ids.length; i < len; ++i) {
+ id = ids[i];
+ idx = Tegaki.getLayerIndex(id);
+ sel.removeChild(sel.options[Tegaki.layers.length - 1 - idx]);
+ Tegaki.layersCnt.removeChild(Tegaki.layers[idx].canvas);
+
+ indices.push(idx);
+ layers.push(Tegaki.layers[idx]);
+
+ Tegaki.layers.splice(idx, 1);
+ }
+
+ Tegaki.setActiveLayer();
+
+ return new TegakiHistoryActions.DestroyLayers(indices, layers);
+ },
+
+ mergeLayers: function(ids) {
+ var i, id, sel, idx, canvasBefore, destId, dest, action;
+
+ sel = T$.id('tegaki-layer');
+
+ destId = ids.pop();
+ idx = Tegaki.getLayerIndex(destId);
+ dest = Tegaki.layers[idx].ctx;
+
+ canvasBefore = T$.copyCanvas(Tegaki.layers[idx].canvas);
+
+ for (i = ids.length - 1; i >= 0; i--) {
+ id = ids[i];
+ idx = Tegaki.getLayerIndex(id);
+ dest.drawImage(Tegaki.layers[idx].canvas, 0, 0);
+ }
+
+ action = Tegaki.deleteLayers(ids);
+ action.layerId = destId;
+ action.canvasBefore = canvasBefore;
+ action.canvasAfter = T$.copyCanvas(dest.canvas);
+
+ Tegaki.setActiveLayer(destId);
+
+ return action;
+ },
+
+ moveLayer: function(id, up) {
+ var idx, sel, opt, canvas, tmp, tmpId;
+
+ sel = T$.id('tegaki-layer');
+ idx = Tegaki.getLayerIndex(id);
+
+ canvas = Tegaki.layers[idx].canvas;
+ opt = sel.options[Tegaki.layers.length - 1 - idx];
+
+ if (up) {
+ if (!Tegaki.ghostCanvas.nextElementSibling) { return false; }
+ canvas.parentNode.insertBefore(canvas,
+ Tegaki.ghostCanvas.nextElementSibling.nextElementSibling
+ );
+ opt.parentNode.insertBefore(opt, opt.previousElementSibling);
+ tmpId = idx + 1;
+ }
+ else {
+ if (canvas.previousElementSibling.id === 'tegaki-canvas') { return false; }
+ canvas.parentNode.insertBefore(canvas, canvas.previousElementSibling);
+ opt.parentNode.insertBefore(opt, opt.nextElementSibling.nextElementSibling);
+ tmpId = idx - 1;
+ }
+
+ Tegaki.updateGhostLayerPos();
+
+ tmp = Tegaki.layers[tmpId];
+ Tegaki.layers[tmpId] = Tegaki.layers[idx];
+ Tegaki.layers[idx] = tmp;
+
+ Tegaki.activeLayer = tmpId;
+
+ return new TegakiHistoryActions.MoveLayer(id, up);
+ },
+
+ setLayerVisibility: function(ids, flag) {
+ var i, len, sel, idx, layer, optIdx;
+
+ sel = T$.id('tegaki-layer');
+ optIdx = Tegaki.layers.length - 1;
+
+ for (i = 0, len = ids.length; i < len; ++i) {
+ idx = Tegaki.getLayerIndex(ids[i]);
+ layer = Tegaki.layers[idx];
+ layer.visible = flag;
+
+ if (flag) {
+ sel.options[optIdx - idx].classList.remove('tegaki-strike');
+ layer.canvas.classList.remove('tegaki-hidden');
+ }
+ else {
+ sel.options[optIdx - idx].classList.add('tegaki-strike');
+ layer.canvas.classList.add('tegaki-hidden');
+ }
+ }
+ },
+
+ setActiveLayer: function(id) {
+ var ctx, idx;
+
+ idx = id ? Tegaki.getLayerIndex(id) : Tegaki.layers.length - 1;
+
+ if (idx < 0 || idx > Tegaki.maxLayers) {
+ return;
+ }
+
+ ctx = Tegaki.layers[idx].ctx;
+
+ if (Tegaki.activeCtx) {
+ Tegaki.copyContextState(Tegaki.activeCtx, ctx);
+ }
+
+ Tegaki.activeCtx = ctx;
+ Tegaki.activeLayer = idx;
+ T$.id('tegaki-layer').selectedIndex = Tegaki.layers.length - idx - 1;
+
+ Tegaki.updateGhostLayerPos();
+ },
+
+ updateGhostLayerPos: function() {
+ Tegaki.layersCnt.insertBefore(
+ Tegaki.ghostCanvas,
+ Tegaki.activeCtx.canvas.nextElementSibling
+ );
+ },
+
+ copyContextState: function(src, dest) {
+ var i, p, props = [
+ 'lineCap', 'lineJoin', 'strokeStyle', 'fillStyle', 'globalAlpha',
+ 'lineWidth', 'globalCompositeOperation'
+ ];
+
+ for (i = 0; p = props[i]; ++i) {
+ dest[p] = src[p];
+ }
+ },
+
+ updateCursor: function() {
+ var radius;
+
+ radius = 0 | (Tegaki.tool.size / 2);
+
+ if (Tegaki.tool.noCursor || radius < 1) {
+ Tegaki.layersCnt.style.cursor = 'default';
+ return;
+ }
+
+ Tegaki.layersCnt.style.cursor = 'url("'
+ + Tegaki.renderCircle(radius).toDataURL('image/png')
+ + '") 16 16, default';
+ },
+
+ updatePosOffset: function() {
+ var aabb = Tegaki.canvas.getBoundingClientRect();
+ Tegaki.offsetX = aabb.left + window.pageXOffset + Tegaki.cnt.scrollLeft;
+ Tegaki.offsetY = aabb.top + window.pageYOffset + Tegaki.cnt.scrollTop;
+ },
+
+ onMouseMove: function(e) {
+ if (Tegaki.isPainting) {
+ Tegaki.tool.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1));
+ }
+ else if (Tegaki.isColorPicking) {
+ TegakiPipette.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1));
+ }
+ },
+
+ onMouseDown: function(e) {
+ if (e.target.parentNode === Tegaki.layersCnt) {
+ if (Tegaki.activeLayer === null) {
+ alert(TegakiStrings.noActiveLayer);
+ return;
+ }
+ if (!Tegaki.layers[Tegaki.activeLayer].visible) {
+ alert(TegakiStrings.hiddenActiveLayer);
+ return;
+ }
+ }
+ else if (e.target !== Tegaki.bg) {
+ return;
+ }
+
+ if (e.which === 3 || e.altKey) {
+ Tegaki.isColorPicking = true;
+ TegakiPipette.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1));
+ }
+ else {
+ Tegaki.isPainting = true;
+ TegakiHistory.pendingAction = new TegakiHistoryActions.Draw(
+ Tegaki.layers[Tegaki.activeLayer].id
+ );
+ TegakiHistory.pendingAction.addCanvasState(Tegaki.activeCtx.canvas, 0);
+ Tegaki.tool.draw(Tegaki.getCursorPos(e, 0), Tegaki.getCursorPos(e, 1), true);
+ }
+ },
+
+ onMouseUp: function(e) {
+ if (Tegaki.isPainting) {
+ Tegaki.tool.commit && Tegaki.tool.commit();
+ TegakiHistory.pendingAction.addCanvasState(Tegaki.activeCtx.canvas, 1);
+ TegakiHistory.push(TegakiHistory.pendingAction);
+ Tegaki.isPainting = false;
+ }
+ else if (Tegaki.isColorPicking) {
+ e.preventDefault();
+ Tegaki.isColorPicking = false;
+ }
+ },
+
+ onDummy: function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+};
+
+// Bienvenido a Internet
+function topen() {
+ console.log(document.forms["imgform"].dataset.w);
+ console.log(document.forms["imgform"].dataset.h);
+ Tegaki.open({
+ onDone: function() {
+ document.getElementById('status').innerHTML = 'Subiendo...';
+ document.getElementById('buttons').style.display = 'none';
+ document.getElementById('links').style.display = 'none';
+ document.getElementById('filebase').value = Tegaki.flatten().toDataURL('image/png');
+ document.forms["imgform"].submit();
+ },
+ onCancel: function() { history.back(-1); },
+ width: document.forms["imgform"].dataset.w,
+ height: document.forms["imgform"].dataset.h
+ });
+}
+window.onload = function() {
+ document.getElementById('topen').addEventListener('click', topen);
+ topen();
+}; \ No newline at end of file
diff --git a/static/js/weabot.js b/static/js/weabot.js
new file mode 100644
index 0000000..0adc2e1
--- /dev/null
+++ b/static/js/weabot.js
@@ -0,0 +1,456 @@
+var style_cookie = 'weabot_style_ib';
+
+function set_stylesheet(styletitle) {
+ var css=document.getElementById("css");
+ if(css) {
+ css.href = "/static/css/" + styletitle.toLowerCase() + ".css";
+ localStorage.setItem(style_cookie, styletitle);
+ }
+}
+
+if(style_cookie && localStorage.hasOwnProperty(style_cookie)) {
+ set_stylesheet(localStorage.getItem(style_cookie));
+}
+
+var hiddenthreads = Array();
+/* IE/Opera fix, because they need to go learn a book on how to use indexOf with arrays */
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(elt /*, from*/) {
+ var len = this.length;
+ var from = Number(arguments[1]) || 0;
+ from = (from < 0) ? Math.ceil(from) : Math.floor(from);
+ if (from < 0) from += len;
+ for (; from < len; from++) {
+ if (from in this && this[from] === elt) return from;
+ }
+ return -1;
+ };
+}
+
+function timeAgo(timestamp) {
+ var time = Math.round(Date.now()/1000);
+ var el = time - timestamp;
+ if (el==0) return "un instante";
+ else if (el==1) return "un segundo";
+ else if (el<60) return el + " segundos";
+ else if (el<120) return "un minuto";
+ else if (el<3600) return Math.round(el/60) + " minutos";
+ else if (el<7200) return "una hora";
+ else if (el<86400) return Math.round(el/3600) + " horas";
+ else if (el<172800) return "un día";
+ else if (el<2628000) return Math.round(el/86400) + " días";
+ else if (el<5256000) return "un mes";
+ else if (el<31536000) return Math.round(el/2628000) + " meses";
+ else if (el>31535999) return "más de un año";
+}
+
+function localTime(timestamp, id) {
+ id = id || 0;
+ var lcl = new Date(timestamp*1000);
+ lcl = ("0"+lcl.getDate()).slice(-2) + "/" + ("0" + (lcl.getMonth()+1)).slice(-2) + "/" + lcl.getFullYear().toString().slice(-2) + "(" + week[lcl.getDay()] + ")" + ("0"+lcl.getHours()).slice(-2) + ":" + ("0"+lcl.getMinutes()).slice(-2) + ":" + ("0"+lcl.getSeconds()).slice(-2)
+ if (id) lcl = lcl + " " + id;
+ return lcl;
+}
+
+function postClick(e) {
+ e.preventDefault();
+ var sel = window.getSelection().toString();
+ if (sel) sel = sel.replace(/^/gm, ">") + "\n";
+ insert(">>" + this.textContent + "\n" + sel);
+}
+
+function insert(text) {
+ var textarea=document.forms.postform.message;
+ if(textarea) {
+ if(textarea.createTextRange && textarea.caretPos) { // IE
+ var caretPos=textarea.caretPos;
+ caretPos.text=caretPos.text.charAt(caretPos.text.length-1)==" "?text+" ":text;
+ } else if(textarea.setSelectionRange) { // Firefox
+ var start=textarea.selectionStart;
+ var end=textarea.selectionEnd;
+ textarea.value=textarea.value.substr(0,start)+text+textarea.value.substr(end);
+ textarea.setSelectionRange(start+text.length,start+text.length);
+ } else { textarea.value+=text+" "; }
+ textarea.focus();
+ }
+ return false;
+}
+
+function quote(b, a) {
+ var v = eval("document." + a + ".message");
+ v.value += ">>" + b + "a\ndfs";
+ v.focus();
+}
+
+function checkhighlight() {
+ var match;
+ if(match=/#i([0-9]+)/.exec(document.location.toString()))
+ if(!document.forms.postform.message.value)
+ insert(">>"+match[1]+"\r\n");
+ if(match=/#([0-9]+)/.exec(document.location.toString()))
+ highlight(match[1]);
+}
+
+function highlight(post) {
+ var cells = document.getElementsByClassName("reply");
+ for(var i=0;i<cells.length;i++) if(cells[i].className == "reply highlight") cells[i].className = "reply";
+ var reply = document.getElementById("reply" + post);
+ if(reply) {
+ reply.className = "reply highlight";
+ var match = /^([^#]*)/.exec(document.location.toString());
+ document.location = match[1] + "#" + post;
+ }
+}
+
+function expandimg(e) {
+ var post_id = this.dataset.id;
+ var img_url = this.href;
+ var thumb_url = this.dataset.thumb;
+ var img_w = parseInt(this.dataset.w);
+ var img_h = parseInt(this.dataset.h);
+ var thumb_w = parseInt(this.dataset.tw);
+ var thumb_h = parseInt(this.dataset.th);
+ var format = img_url.substring(img_url.lastIndexOf(".")+1, img_url.length);
+ var exp_vid = 0;
+
+ if(window.innerWidth > 900) var ratio = Math.min((window.innerWidth-130) / img_w, 1);
+ else var ratio = Math.min((window.innerWidth-40) / img_w, 1);
+
+ if(thumb_w < 1) return true;
+
+ var img_cont = document.getElementById("thumb" + post_id);
+ var post_block = img_cont.parentElement.parentElement.getElementsByTagName("blockquote")[0];
+ var img;
+
+ for(var i = 0; i < img_cont.childNodes.length; i++)
+ if(img_cont.childNodes[i].nodeName.toLowerCase() == "img") {
+ img = img_cont.childNodes[i];
+ } else if(img_cont.childNodes[i].nodeName.toLowerCase() == "video") {
+ img = img_cont.childNodes[i];
+ exp_vid = 1;
+ }
+
+ if(img) {
+ if( (format == "webm") && (exp_vid == 0) ) var new_img = document.createElement("video");
+ else var new_img = document.createElement("img");
+ new_img.setAttribute("class", "thumb");
+ new_img.setAttribute("alt", "" + post_id);
+
+ if( (img.getAttribute("width") == ("" + thumb_w)) && (img.getAttribute("height") == ("" + thumb_h)) ) {
+ // thumbnail -> fullsize
+ if(format == "webm") {
+ new_img.setAttribute("controls", "");
+ new_img.setAttribute("loop", "");
+ new_img.setAttribute("autoplay", "");
+ }
+ new_img.setAttribute("src", "" + img_url);
+ new_img.setAttribute("width", img_w);
+ new_img.setAttribute("height", img_h);
+ new_img.setAttribute("style", "max-width:"+Math.floor((img_w*ratio))+"px;max-height:"+Math.floor((img_h*ratio))+"px;");
+ post_block.setAttribute("style", "");
+ img_cont.style.display = 'table';
+ } else {
+ // fullsize -> thumbnail
+ if(format == "webm") {
+ new_img.removeAttribute("controls");
+ new_img.removeAttribute("loop");
+ new_img.removeAttribute("autoplay");
+ }
+ new_img.setAttribute("src", "" + thumb_url);
+ new_img.setAttribute("width", thumb_w);
+ new_img.setAttribute("height", thumb_h);
+ post_block.setAttribute("style", "margin-left:"+(parseInt(thumb_w)+40)+"px;max-width:"+(1000-parseInt(thumb_w))+"px");
+ img_cont.removeAttribute("style");
+ }
+
+ while(img_cont.lastChild) img_cont.removeChild(img_cont.lastChild);
+
+ img_cont.appendChild(new_img);
+ e.preventDefault();
+ }
+}
+
+function filePreview(e) {
+ var file = postform.file.files[0];
+ var inpt = document.getElementById("file");
+ var prev = document.getElementById("filepreview");
+ var noimg = document.getElementById("noimage");
+ if (noimg) noimg = document.getElementById("noimage").parentNode;
+ if (file.size > (maxsize*1024)) { inpt.value = ""; return alert("El archivo es muy grande. El tamaño máximo es " + maxsize + " KB."); }
+ if (!types.includes(inpt.value.slice(inpt.value.lastIndexOf(".")+1).toUpperCase())) { inpt.value = ""; return alert("Tipo de archivo no soportado."); }
+ var read = new FileReader();
+ read.readAsDataURL(file);
+ read.onload = function(){
+ inpt.style.display = "none";
+ if (noimg) noimg.style.display = "none";
+ prev.removeAttribute("style");
+ var fname = (file.name.length < 20) ? file.name : file.name.substr(0, 19) + "…";
+ if (file.type.startsWith("image")) prev.insertAdjacentHTML('beforeend', '<img class="thumbpreview" src="' + read.result + '" /> ' + fname);
+ else prev.insertAdjacentHTML('beforeend', fname);
+ prev.appendChild(document.createTextNode(" ["));
+ var btn = document.createElement("a");
+ btn.href = "#";
+ btn.innerText = "Quitar"
+ btn.addEventListener("click", function(e) {
+ e.preventDefault();
+ prev.innerHTML = "";
+ prev.style.display = "none";
+ inpt.removeAttribute("style");
+ if (noimg) noimg.removeAttribute("style");
+ inpt.value = "";
+ });
+ prev.appendChild(btn);
+ prev.appendChild(document.createTextNode("] "));
+ };
+}
+
+function togglethread(e) {
+ e.preventDefault();
+ if(this.parentElement.id.startsWith("unhide")) {
+ var threadid = this.parentElement.id.substr(6);
+ } else if(this.parentElement.parentElement.id.startsWith("thread")) {
+ var threadid = this.parentElement.parentElement.id.substr(6);
+ } else { return; }
+ if (hiddenthreads.toString().indexOf(threadid) !== -1) {
+ document.getElementById("unhide" + threadid).style.display = "none";
+ document.getElementById("thread" + threadid).removeAttribute("style");
+ hiddenthreads.splice(hiddenthreads.indexOf(threadid), 1);
+ } else {
+ document.getElementById("unhide" + threadid).removeAttribute("style");
+ document.getElementById("thread" + threadid).style.display = "none";
+ hiddenthreads.push(threadid);
+ }
+ if (hiddenthreads == "") localStorage.removeItem("hiddenthreads");
+ else localStorage.setItem("hiddenthreads", hiddenthreads.join("!"));
+}
+
+function saveInputs(e) {
+ var e = e || window.event;
+ var form = e.target || e.srcElement;
+ if(typeof(form.fielda) !== "undefined") weabot.name = form.fielda.value;
+ if(typeof(form.fielda) !== "undefined") weabot.email = form.fieldb.value;
+ localStorage.setItem("weabot", JSON.stringify(weabot));
+}
+
+function setInputs(id) {
+ if (document.getElementById(id)) {
+ with(document.getElementById(id)) {
+ if(typeof(fielda) !== 'undefined' && !fielda.value && weabot.name) fielda.value = weabot.name;
+ if(typeof(fielda) !== 'undefined' && !fieldb.value && weabot.email) fieldb.value = weabot.email;
+ if(!password.value) password.value = getPassword();
+ addEventListener("submit", saveInputs);
+ }
+ }
+}
+
+function setPassword(id) {
+ if (document.getElementById(id).password)
+ with (document.getElementById(id)) if(!password.value) password.value = getPassword("weabot_password");
+}
+
+function getPassword() {
+ if (weabot.password) return weabot.password;
+ var char="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ var pass="";
+ for (var i=0;i<8;i++) {
+ var rnd = Math.floor(Math.random()*char.length);
+ pass += char.substring(rnd, rnd+1);
+ }
+ weabot.password = pass;
+ localStorage.setItem("weabot", JSON.stringify(weabot));
+ return(pass);
+}
+
+function catSort(type) {
+ for(var i=0;i<srt.length;i++) srt[i].innerHTML=srt[i].innerText;
+ srt[type].innerHTML = "<b>"+srt[type].innerText+"</b>";
+ var cont = document.getElementById("catalog");
+ var elem = document.getElementsByClassName("thread");
+ var arr = Array.prototype.slice.call(elem);
+ if (type==0) arr.sort(function (a,b) { return (a.dataset.num-b.dataset.num) });
+ else if (type==1) arr.sort(function (a,b) { return (b.dataset.id-a.dataset.id) });
+ else if (type==2) arr.sort(function (a,b) { return (a.dataset.id-b.dataset.id) });
+ else if (type==3) arr.sort(function (a,b) { return (b.dataset.res-a.dataset.res) });
+ else if (type==4) arr.sort(function (a,b) { return (a.dataset.res-b.dataset.res) });
+ for (var j=0;j<arr.length;j++) cont.appendChild(arr[j]);
+ localStorage.setItem("catalog", JSON.stringify(opcs));
+}
+
+function catSearch() {
+ var filter = document.getElementById("cat_search").value.toLowerCase();
+ var nodes = document.getElementsByTagName("p");
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].innerText.toLowerCase().includes(filter))
+ nodes[i].parentNode.removeAttribute("style");
+ else nodes[i].parentNode.style.display = "none";
+ }
+}
+
+function catThumbs(big) {
+ var btn = document.getElementById("cat_size");
+ var cat = document.getElementById("catalog");
+ var threads = document.getElementsByClassName("thread");
+ if (opcs.big) {
+ cat.className = "enlarged";
+ for (j = 0; j < threads.length; j++) {
+ img = threads[j].getElementsByTagName("a")[0];
+ img.innerHTML = img.innerHTML.replace("/cat/", "/thumb/");
+ }
+ btn.innerText = "Grande";
+ } else {
+ cat.removeAttribute("class");
+ for (j = 0; j < threads.length; j++) {
+ img = threads[j].getElementsByTagName("a")[0];
+ img.innerHTML = img.innerHTML.replace("/thumb/", "/cat/");
+ }
+ btn.innerText = "Pequeño";
+ }
+ localStorage.setItem("catalog", JSON.stringify(opcs));
+}
+
+function catTeasers(teaser) {
+ var btn = document.getElementById("cat_hide");
+ if (!teaser) {
+ var style = document.createElement("style");
+ style.id = "teaser_style";
+ style.type = "text/css";
+ style.innerText = '#catalog p{display:none}';
+ document.head.appendChild(style);
+ btn.innerText = "Mostrar";
+ } else {
+ var style = document.getElementById("teaser_style");
+ if (style) style.parentNode.removeChild(style);
+ btn.innerText = "Ocultar";
+ }
+ localStorage.setItem("catalog", JSON.stringify(opcs));
+}
+
+function catMenu(e) {
+ var brd = document.getElementsByName("board")[0].value;
+ var id = this.dataset.id;
+ this.insertAdjacentHTML('afterbegin', '<div id="thread_ctrl" style="margin-bottom:3px;">[<a href="/cgi/report/' + brd + '/' + id + '">Denunciar</a>] [<a href="#" class="hh">Ocultar</a>]');
+ this.getElementsByClassName("hh")[0].addEventListener("click", function(e) {
+ document.getElementById("cat" + id + brd).style.display = "none";
+ hiddenthreads.push(id + brd);
+ localStorage.setItem("hiddenthreads", hiddenthreads.join("!"))
+ if (document.getElementById("hidden_label")) { hidden_num++; document.getElementById("hidden_num").innerText = hidden_num; }
+ else { hidden_num = 1; catHidden(); }
+ });
+}
+
+function catMenuClose(e) { document.getElementById("thread_ctrl").remove(); }
+
+function catHidden() {
+ var menu = document.getElementById("ctrl");
+ menu.insertAdjacentHTML('beforeend', ' <span id="hidden_label">[Hilos ocultos: <span id="hidden_num">' + hidden_num + '</span> - ');
+ var lbl = document.getElementById("hidden_label");
+ var shw = document.createElement("a");
+ shw.href = "#"; shw.innerText = "Deshacer";
+ shw.addEventListener("click", function(e) {
+ e.preventDefault();
+ for(var i=0;i<hiddenthreads.length;i++){
+ try {document.getElementById("cat" + hiddenthreads[i]).removeAttribute("style");}
+ catch(err) { continue; } }
+ lbl.parentElement.removeChild(lbl); hidden_num = 0;
+ var aux = hiddenthreads.join("!");
+ var exp = new RegExp("\\b[0-9]+" + document.getElementsByName("board")[0].value + "\\b", "g");
+ aux = aux.replace(exp, "!"); aux = aux.replace(/!+/g, "!"); aux = aux.replace(/(^!|!$)/g, "");
+ if (aux == "") { localStorage.removeItem("hiddenthreads"); hiddenthreads = []; }
+ else { localStorage.setItem("hiddenthreads", aux); hiddenthreads = aux.split("!"); }
+ });
+ lbl.appendChild(shw); lbl.appendChild(document.createTextNode("]"));
+}
+
+document.addEventListener("DOMContentLoaded", function(e) {
+ checkhighlight();
+ if (localStorage.hasOwnProperty("weabot")) weabot = JSON.parse(localStorage.getItem("weabot"));
+ else weabot = {"name":null,"email":null,"password":null};
+
+ if(localStorage.hasOwnProperty("hiddenthreads")) {
+ hiddenthreads = localStorage.getItem("hiddenthreads").split("!");
+ if (document.getElementById("catalog")) {
+ hidden_num = 0;
+ for(var i=0;i<hiddenthreads.length;i++){
+ try {
+ document.getElementById("cat" + hiddenthreads[i]).style.display = "none";
+ hidden_num++;
+ } catch(err) { continue; }
+ }
+ if (hidden_num) { catHidden(); }
+ } else {
+ for(var i=0;i<hiddenthreads.length;i++){
+ try {
+ document.getElementById("unhide" + hiddenthreads[i]).removeAttribute("style");
+ document.getElementById("thread" + hiddenthreads[i]).style.display = "none";
+ } catch(err) { continue; }
+ }
+ }
+ }
+
+ if(localStorage.getItem("shobon_time") != "false") {
+ var dts = document.getElementsByClassName("date");
+ if (dts[0].dataset.unix) {
+ week = ["dom", "lun", "mar", "mie", "jue", "vie", "sab"];
+ if (document.getElementsByName("board")[0].value == "2d") week = ["日", "月", "火", "水", "木", "金", "土"];
+ for(var d=0;d<dts.length;d++) {
+ dts[d].addEventListener("mouseover", function(e) { this.title = "Hace " + timeAgo(this.dataset.unix); });
+ if (dts[d].innerText.includes("ID:")) var id = dts[d].innerText.split(" ")[1];
+ dts[d].innerText = localTime(dts[d].dataset.unix, id);
+ }
+ }
+ }
+
+ var ids = document.getElementsByClassName("postid");
+ for(var i=0;i<ids.length;i++) {
+ ids[i].addEventListener('click', postClick);
+ }
+ var tts = document.getElementsByClassName("tt");
+ for(var i=0;i<tts.length;i++) {
+ tts[i].addEventListener('click', togglethread);
+ }
+ var tts = document.getElementsByClassName("expimg");
+ for(var i=0;i<tts.length;i++) {
+ tts[i].addEventListener('click', expandimg);
+ }
+ var sss = document.getElementsByClassName("ss");
+ for(var i=0;i<sss.length;i++) {
+ sss[i].addEventListener('click', function() {
+ var cur = document.getElementById("cur_stl");
+ set_stylesheet(this.textContent);
+ if (cur) cur.removeAttribute("id");
+ this.id = "cur_stl";
+ });
+ if (sss[i].innerText == localStorage.getItem(style_cookie)) sss[i].id = "cur_stl";
+ }
+
+ if (document.getElementById(document.getElementsByName("board")[0].value))
+ document.getElementById(document.getElementsByName("board")[0].value).className = "cur_brd";
+
+ if (document.getElementById("postform")) {
+ setInputs("postform");
+ setPassword("delform");
+ maxsize = document.getElementById("maxsize").innerText;
+ types = document.getElementById("filetypes").innerText.split(", ");
+ if (types.includes("JPG")) types.push("JPEG");
+ postform.file.addEventListener("change", filePreview);
+ }
+
+ window.addEventListener("hashchange", checkhighlight);
+
+ if (document.getElementById("catalog")) {
+ srt = document.getElementsByClassName("cat_sort");
+ for(var i=0;i<srt.length;i++) { srt[i].innerHTML=srt[i].innerText; srt[i].addEventListener("click", function(e) { e.preventDefault(); opcs.sort=this.dataset.sort; catSort(opcs.sort); }); }
+ document.getElementById("cat_size").addEventListener("click", function(e) { e.preventDefault(); opcs.big=!opcs.big; catThumbs(opcs.big); });
+ document.getElementById("cat_hide").addEventListener("click", function(e) { e.preventDefault(); opcs.teaser=!opcs.teaser; catTeasers(opcs.teaser); });
+ document.getElementById("cat_search").addEventListener("keyup", catSearch);
+ if (localStorage.hasOwnProperty("catalog")) {
+ opcs = JSON.parse(localStorage.getItem("catalog"));
+ if(match=/\?sort=([0-9])/.exec(document.location.toString())) opcs.sort=match[1];
+ catSort(opcs.sort); catThumbs(opcs.big); catTeasers(opcs.teaser);
+ } else {
+ opcs = {"sort":1,"big":false,"teaser":true}; localStorage.setItem("catalog", JSON.stringify(opcs));
+ }
+ var thr = document.getElementsByClassName("thread");
+ for(var i=0;i<thr.length;i++) { thr[i].addEventListener("mouseenter", catMenu); thr[i].addEventListener("mouseleave", catMenuClose); }
+ }
+}); \ No newline at end of file
diff --git a/static/js/weabotxt.js b/static/js/weabotxt.js
new file mode 100644
index 0000000..37668d8
--- /dev/null
+++ b/static/js/weabotxt.js
@@ -0,0 +1,299 @@
+var style_cookie = "weabot_style_txt";
+if(style_cookie && localStorage.hasOwnProperty(style_cookie)) { set_stylesheet(localStorage.getItem(style_cookie)); }
+
+var hiddenposts = Array();
+
+function set_stylesheet(styletitle) {
+ var css=document.getElementById("css");
+ if(css) css.href = "/static/css/txt/"+styletitle.toLowerCase()+".css";
+ localStorage.setItem(style_cookie,styletitle);
+}
+
+function changeDate() {
+ var dts = document.getElementsByClassName("date");
+ if (dts[0].dataset.unix) {
+ week = ["dom", "lun", "mar", "mie", "jue", "vie", "sab"];
+ if (board == "world") week = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
+ for(var d=0;d<dts.length;d++) {
+ dts[d].addEventListener('mouseover', function(e) { this.title = "Hace " + timeAgo(this.dataset.unix); });
+ if (dts[d].innerText.includes("ID:")) var id = dts[d].innerText.split(" ")[1];
+ dts[d].innerText = localTime(dts[d].dataset.unix, id);
+ }
+ }
+}
+
+function timeAgo(timestamp) {
+ var time = Math.round(Date.now()/1000);
+ var el = time - timestamp;
+ if (el==0) return "un instante";
+ else if (el==1) return "un segundo";
+ else if (el<60) return el + " segundos";
+ else if (el<120) return "un minuto";
+ else if (el<3600) return Math.round(el/60) + " minutos";
+ else if (el<7200) return "una hora";
+ else if (el<86400) return Math.round(el/3600) + " horas";
+ else if (el<172800) return "un día";
+ else if (el<2628000) return Math.round(el/86400) + " días";
+ else if (el<5256000) return "un mes";
+ else if (el<31536000) return Math.round(el/2628000) + " meses";
+ else if (el>31535999) return "más de un año";
+}
+
+function localTime(timestamp, id) {
+ id = id || 0;
+ var lcl = new Date(timestamp*1000);
+ lcl = ("0"+lcl.getDate()).slice(-2) + "/" + ("0" + (lcl.getMonth()+1)).slice(-2) + "/" + lcl.getFullYear().toString().slice(-2) + "(" + week[lcl.getDay()] + ")" + ("0"+lcl.getHours()).slice(-2) + ":" + ("0"+lcl.getMinutes()).slice(-2) + ":" + ("0"+lcl.getSeconds()).slice(-2)
+ if (id) lcl = lcl + " " + id;
+ return lcl;
+}
+
+/* IE/Opera fix, because they need to go learn a book on how to use indexOf with arrays */
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(elt /*, from*/) {
+ var len = this.length;
+ var from = Number(arguments[1]) || 0;
+ from = (from < 0) ? Math.ceil(from) : Math.floor(from);
+ if (from < 0) from += len;
+ for (; from < len; from++) { if (from in this && this[from] === elt) return from; }
+ return -1;
+ };
+}
+
+function getPassword() {
+ if (weabot.password) return weabot.password;
+ var char="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ var pass="";
+ for (var i=0;i<8;i++) {
+ var rnd = Math.floor(Math.random()*char.length);
+ pass += char.substring(rnd, rnd+1);
+ }
+ weabot.password = pass;
+ localStorage.setItem("weabot", JSON.stringify(weabot));
+ return(pass);
+}
+
+function saveInputs(e) {
+ var e = e || window.event;
+ var form = e.target || e.srcElement;
+ if(typeof(form.fielda) !== "undefined") weabot.name = form.fielda.value;
+ if(typeof(form.fielda) !== "undefined") weabot.email = form.fieldb.value;
+ localStorage.setItem("weabot", JSON.stringify(weabot));
+}
+
+function setInputs(id) {
+ if (document.getElementById(id)) {
+ with(document.getElementById(id)) {
+ if(typeof(fielda) !== 'undefined' && !fielda.value && weabot.name) fielda.value = weabot.name;
+ if(typeof(fielda) !== 'undefined' && !fieldb.value && weabot.email) fieldb.value = weabot.email;
+ if(!password.value) password.value = getPassword();
+ if(typeof preview !== 'undefined') { preview.id = id; preview.addEventListener("click", previewPost); }
+ addEventListener("submit", saveInputs);
+ }
+ }
+}
+
+function setPassword(id) {
+ if (document.getElementById(id).password)
+ with (document.getElementById(id))
+ if(!password.value) password.value = getPassword("weabot_password");
+}
+
+// Textboard data
+function insert(text) {
+ var textarea=document.forms.postform.message;
+ if(textarea) {
+ if(textarea.createTextRange && textarea.caretPos) { // IE
+ var caretPos=textarea.caretPos;
+ caretPos.text=caretPos.text.charAt(caretPos.text.length-1)==" "?text+" ":text;
+ } else if(textarea.setSelectionRange) { // Firefox
+ var start=textarea.selectionStart;
+ var end=textarea.selectionEnd;
+ textarea.value=textarea.value.substr(0,start)+text+textarea.value.substr(end);
+ textarea.setSelectionRange(start+text.length,start+text.length);
+ } else {
+ textarea.value+=text+" ";
+ }
+ textarea.focus();
+ }
+ return false;
+}
+
+function deletePost(e) {
+ var ids = this.parentElement.firstChild.href.split("/");
+ var post = ids.pop();
+ var realid = ids.pop();
+ if(confirm("¿Seguro que deseas borrar el mensaje "+post+"?")) {
+ var script="/cgi/delete";
+ document.location=script+"?board="+board+"&password="+weabot.password+"&delete="+realid;
+ }
+ e.preventDefault();
+}
+
+function postClick(e) {
+ e.preventDefault();
+ var sel = window.getSelection().toString();
+ if (sel) { sel=sel.replace(/^/gm, ">")+"\n"; sel="\n"+sel; }
+ insert(">>" + this.textContent + sel);
+}
+
+function previewPost(e) {
+ var formid = e.target.id;
+ var thread = "0";
+ if(formid.startsWith("postform")) thread = formid.substr(8);
+
+ var form=document.getElementById(formid);
+ var preview=document.getElementById("preview"+thread);
+ var main=document.getElementById("options");
+
+ if(!form||!preview||!form.message.value) return;
+ if(main) main.style.display="";
+
+ preview.removeAttribute("style");
+ preview.innerHTML="<em>Cargando...</em>";
+
+ var text="message="+encodeURIComponent(form.message.value)+"&board="+board;
+ if (thread) text+="&parentid="+thread;
+
+ var xmlhttp=get_xmlhttp();
+ xmlhttp.open("POST", "/cgi/preview");
+ xmlhttp.onreadystatechange=function() { if(xmlhttp.readyState==4) preview.innerHTML=xmlhttp.responseText; }
+ if(is_ie()||xmlhttp.setRequestHeader) xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
+ xmlhttp.send(text);
+}
+
+function listSort() {
+ var s = opcs.sort;
+ var cont = document.getElementById("content");
+ var elem = document.getElementsByClassName("row");
+ var arr = Array.prototype.slice.call(elem); arr.shift();
+ if (s=="Normal") { arr.sort(function (a,b) { return (parseInt(a.childNodes[1].innerText) - parseInt(b.childNodes[1].innerText)) }); }
+ else if(s=="Edad"){ arr.sort(function (a,b) { return (b.children[1].firstChild.href.split("/")[5] - a.children[1].firstChild.href.split("/")[5]) }); }
+ else if(s=="Largo"){ arr.sort(function (a,b) { return (b.children[2].textContent - a.children[2].textContent) }); }
+ else if(s=="Rapidez"){ var now=Math.round(Date.now()/1000); arr.sort(function (a,b) { return ((b.children[2].textContent/(now-b.children[1].firstChild.href.split("/")[5])) - (a.children[2].textContent/(now-a.children[1].firstChild.href.split("/")[5]))) }); }
+ else if(s=="Aleatorio"){ arr.sort(function(a,b) { return 0.5-Math.random()}); }
+ for (var j=0;j<arr.length;j++) cont.appendChild(arr[j]);
+ localStorage.setItem("threadlist", JSON.stringify(opcs));
+}
+
+function listDisplay() {
+ var d = opcs.disp;
+ if (d=="Malla") {
+ document.getElementById("header").style.display = "none";
+ document.getElementById("content").className = "grid";
+ var style = document.createElement("style");
+ style.id = "labels";
+ style.type = "text/css";
+ style.innerText = '#content .row div.date{display:none}#content.grid div.com:before{content:"("}#content.grid .com:after{content:")"}';
+ document.head.appendChild(style);
+ } else if (d=="Lista") {
+ var style = document.getElementById("labels");
+ if (style) style.parentNode.removeChild(style);
+ document.getElementById("header").removeAttribute("style");
+ document.getElementById("content").className = "list";
+ }
+ localStorage.setItem("threadlist", JSON.stringify(opcs));
+}
+
+function searchSubjects(e) {
+ var filter = this.value.toLowerCase();
+ var nodes = document.getElementsByClassName("thread");
+ for (i=0; i<nodes.length; i++) {
+ if (nodes[i].innerText.toLowerCase().includes(filter)) nodes[i].parentNode.removeAttribute("style");
+ else nodes[i].parentNode.style.display = "none";
+ }
+}
+
+function get_xmlhttp() {
+ var xmlhttp;
+ try { xmlhttp=new ActiveXObject("Msxml2.XMLHTTP"); }
+ catch(e1) {
+ try { xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); }
+ catch(e1) { xmlhttp=null; }
+ }
+ if(!xmlhttp && typeof XMLHttpRequest!='undefined') xmlhttp=new XMLHttpRequest();
+ return(xmlhttp);
+}
+
+function is_ie() { return(document.all&&!document.opera); }
+
+function showpost(post) {
+ post.children[0].classList.remove("hidden");
+ post.children[1].style.display = 'block';
+}
+function hidepost(post) {
+ post.children[0].classList.add("hidden");
+ post.children[1].style.display = 'none';
+}
+function togglepost(e) {
+ e.preventDefault();
+ var post = this.parentElement;
+ var postid = board + this.getElementsByClassName("date")[0].dataset.unix;
+
+ if(post.children[1].style.display == 'none') {
+ showpost(post);
+ if(hiddenposts.includes(postid)) hiddenposts.splice(hiddenposts.indexOf(postid), 1);
+ } else {
+ hidepost(post);
+ if(!hiddenposts.includes(postid)) hiddenposts.push(postid);
+ }
+
+ localStorage.setItem("hiddenposts", hiddenposts.join("!"));
+}
+
+document.addEventListener("DOMContentLoaded", function() {
+ if (localStorage.hasOwnProperty("weabot")) weabot = JSON.parse(localStorage.getItem("weabot"));
+ else weabot = {"name":null,"email":null,"password":null};
+
+ board = document.getElementsByName("board")[0].value;
+
+ if(localStorage.getItem("shobon_time") != "false") {
+ changeDate();
+ }
+
+ var ids = document.getElementsByClassName("num");
+ for(var i=0;i<ids.length;i++) ids[i].addEventListener('click', postClick);
+
+ var forms = document.getElementsByTagName("form");
+ for(var i=0;i<forms.length;i++) { if(forms[i].id.startsWith("postform")) setInputs(forms[i].id); }
+
+ var sss = document.getElementsByClassName("ss");
+ var style = localStorage.getItem(style_cookie);
+ for(var i=0;i<sss.length;i++) {
+ sss[i].addEventListener("click", function() {
+ set_stylesheet(this.textContent);
+ var cur = document.getElementById("cur_stl");
+ if (cur) cur.removeAttribute("id");
+ this.id = "cur_stl";
+ });
+ if (sss[i].innerText == style) sss[i].id = "cur_stl";
+ }
+
+ var dds = document.getElementsByClassName("del");
+ for(var i=0;i<dds.length;i++) { dds[i].children[1].addEventListener("click", deletePost); }
+
+ var where = document.getElementById(document.getElementsByName("board")[0].value);
+ if (where) where.className = "cur_brd";
+
+ if (document.body.className == "threads") {
+ var srt = document.getElementsByClassName("l_s");
+ for(var i=0;i<srt.length;i++){ srt[i].addEventListener("click",function(e){ e.preventDefault(); opcs.sort=this.textContent; listSort(); }); }
+ var dsp = document.getElementsByClassName("l_d");
+ for(var i=0;i<dsp.length;i++){ dsp[i].addEventListener("click",function(e){ e.preventDefault(); opcs.disp=this.textContent; listDisplay(); }); }
+ document.getElementById("l_sr").addEventListener("keyup", searchSubjects);
+ if (localStorage.hasOwnProperty("threadlist")) { opcs = JSON.parse(localStorage.getItem("threadlist")); listSort(); listDisplay(); }
+ else { opcs = {"sort":"Normal","disp":"Lista"}; localStorage.setItem("threadlist", JSON.stringify(opcs)); }
+ }
+
+ if(localStorage.hasOwnProperty("hiddenposts"))
+ hiddenposts = localStorage.getItem("hiddenposts").split("!");
+
+ var pps = document.getElementsByClassName("date");
+ for(var i=0;i<pps.length;i++) {
+ if(hiddenposts.includes(board+pps[i].dataset.unix)) {
+ console.log(pps[i].dataset.unix);
+ hidepost(pps[i].parentElement.parentElement);
+ }
+
+ pps[i].parentElement.addEventListener('dblclick', togglepost);
+ }
+}); \ No newline at end of file
diff --git a/static/js/wpaint/.gitignore b/static/js/wpaint/.gitignore
new file mode 100644
index 0000000..7a48116
--- /dev/null
+++ b/static/js/wpaint/.gitignore
@@ -0,0 +1,3 @@
+test/uploads/wPaint-*
+node_modules/
+npm-debug.txt \ No newline at end of file
diff --git a/static/js/wpaint/README.md b/static/js/wpaint/README.md
new file mode 100644
index 0000000..eac4c2a
--- /dev/null
+++ b/static/js/wpaint/README.md
@@ -0,0 +1,421 @@
+# wPaint.js
+
+A jQuery paint plugin for a simple drawing surface that you can easily pop into your pages, similar to the basic windows paint program.
+
+* [View the wPaint demo](http://wpaint.websanova.com)
+* [Download the lastest version of wPaint](https://github.com/websanova/wPaint/tags)
+
+
+## Related Plugins
+
+* [wScratchPad](http://wscratchpad.websanova.com) - Plugin simulating scratch card.
+* [wColorPicker](http://wcolorpicker.websanova.com) - Color pallette seleciton plugin.
+
+
+## Support
+
+If you enjoy this plugin please leave a small contribution on [Gittip](https://gittip.com/websanova). I work on these plugins completely in my free time and any contribution is greatly appreciated.
+
+
+## Settings
+
+Settings are available per plugin. Meaning only when that plugin is included will those settings be available.
+
+### core
+
+```js
+$.fn.wPaint.defaults = {
+ path: '/', // set absolute path for images and cursors
+ theme: 'standard classic', // set theme
+ autoScaleImage: true, // auto scale images to size of canvas (fg and bg)
+ autoCenterImage: true, // auto center images (fg and bg, default is left/top corner)
+ menuHandle: true, // setting to false will means menus cannot be dragged around
+ menuOrientation: 'horizontal', // menu alignment (horizontal,vertical)
+ menuOffsetLeft: 5, // left offset of primary menu
+ menuOffsetTop: 5, // top offset of primary menu
+ bg: null, // set bg on init
+ image: null, // set image on init
+ imageStretch: false, // stretch smaller images to full canvans dimensions
+ onShapeDown: null, // callback for draw down event
+ onShapeMove: null, // callback for draw move event
+ onShapeUp: null // callback for draw up event
+};
+```
+
+### main
+
+```js
+$.extend($.fn.wPaint.defaults, {
+ mode: 'pencil', // set mode
+ lineWidth: '3', // starting line width
+ fillStyle: '#FFFFFF', // starting fill style
+ strokeStyle: '#FFFF00' // start stroke style
+});
+```
+
+### text
+
+```js
+$.extend($.fn.wPaint.defaults, {
+ fontSize : '12', // current font size for text input
+ fontFamily : 'Arial', // active font family for text input
+ fontBold : false, // text input bold enable/disable
+ fontItalic : false, // text input italic enable/disable
+ fontUnderline : false // text input italic enable/disable
+});
+```
+
+### shapes
+
+No settings.
+
+### file
+
+Note that the callbacks for `file` are user generated for the most part as they deal heavily with client/server side code. You can view the demo code to get a feeling for how they might be setup.
+
+```js
+$.extend($.fn.wPaint.defaults, {
+ saveImg: null, // callback triggerd on image save
+ loadImgFg: null, // callback triggered on image fg
+ loadImgBg: null // callback triggerd on image bg
+});
+```
+
+
+## Examples
+
+To start, you will need to include any dependencies (the paths and versions may differ):
+```html
+<!-- jQuery -->
+<script type="text/javascript" src="./lib/jquery.1.10.2.min.js"></script>
+<!-- jQuery UI -->
+<script type="text/javascript" src="./lib/jquery.ui.core.1.10.3.min.js"></script>
+<script type="text/javascript" src="./lib/jquery.ui.widget.1.10.3.min.js"></script>
+<script type="text/javascript" src="./lib/jquery.ui.mouse.1.10.3.min.js"></script>
+<script type="text/javascript" src="./lib/jquery.ui.draggable.1.10.3.min.js"></script>
+<!-- wColorPicker -->
+<link rel="Stylesheet" type="text/css" href="./lib/wColorPicker.min.css" />
+<script type="text/javascript" src="./lib/wColorPicker.min.js"></script>
+```
+
+
+
+Then you need to include the wPaint core files:
+```html
+<link rel="Stylesheet" type="text/css" href="./wPaint.min.css" />
+<script type="text/javascript" src="./wPaint.min.js"></script>
+```
+
+From here we will need to include plugin files for whatever menu icons we would like to support. This can include the plugins provided with the release of this plugin or any additional plugins that you can write on your own.
+
+```html
+<script type="text/javascript" src="./plugins/main/wPaint.menu.main.min.js"></script>
+<script type="text/javascript" src="./plugins/text/wPaint.menu.text.min.js"></script>
+<script type="text/javascript" src="./plugins/shapes/wPaint.menu.main.shapes.min.js"></script>
+<script type="text/javascript" src="./plugins/file/wPaint.menu.main.file.min.js"></script>
+```
+
+
+### path
+
+If you are putting wPaint into a path other than root (most likely you will) then you will need to set the `path` option since the image and cursor icon paths are set in the JavaScript and not in CSS. This means we can not make them relative from the included file like we can in the CSS file but rather relative to the dispalying page. The default path is just the root folder `/` but a path can be set for wpaint.
+
+```js
+$('#wPaint').wPaint({
+ path: '/js/lib/wPaint/'
+});
+```
+
+
+### save / load
+
+There have been many questions regarding saving / loading images using wPaint. Loading images CANNOT be done locally or from other domains due to browser restrictions with [cross origin](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript) policies. There are some potential workarounds for this using [CORS](https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image?redirectlocale=en-US&redirectslug=CORS_Enabled_Image) but this has not been implemented yet.
+
+As it stands the best approach to this is to first upload the image to your server, save it, then use the url from your server to set images in the future. You can check the `upload.php` file in the `test` folder with a php example for saving an image. However note that saving the image on your server will depend on the language/framework being used.
+
+
+### themes
+
+With this release multiple themeing has been introduced by simply space separating multiple theme keywords. For example 'standard classic'. This is to allow us to theme colours and sizes separately and use them interchangeably.
+
+```js
+$("#elem").wPaint({
+ theme: 'standard classic'
+});
+```
+
+
+### image data
+
+Set image on the fly. This can be a base64 encoded image or simply a path to any image on the same domain.
+
+```js
+$('#wPaint').wPaint('image', '<image_data>');
+```
+
+Get the image data:
+
+```js
+var imageData = $("#wPaint").wPaint("image");
+
+$("#canvasImage").attr('src', imageData);
+```
+
+
+### callbacks
+
+There are three callbacks available for each drawing operation of `down`, `move`, and `up`. Available is the `this` object which refers to the `wPaint` object and gives access to all internal functions.
+
+```js
+$("#elem").wPaint({
+ onDrawDown: function (e) {
+ console.log(this.settings.mode + ": " + e.pageX + ',' + e.pageY);
+ },
+ onDrawMove: function (e) {
+ console.log(this.settings.mode + ": " + e.pageX + ',' + e.pageY);
+ },
+ onDrawUp: function (e) {
+ console.log(this.settings.mode + ": " + e.pageX + ',' + e.pageY);
+ }
+});
+```
+
+
+### image / bg
+
+Set the image or background with an image or color at any time.
+
+```js
+$("#wPaint").wPaint({
+ image: './some/path/imagepreload.png',
+ bg: '#ff0000'
+});
+```
+
+
+### resize
+
+In case you want to resize your canvas there is a `resize` utility function available. Call this after you change the dimensions of your canvas element. Check the `test/fullscreen.html` demo for sample code.
+
+```js
+$("#wPaint").wPaint('resize');
+```
+
+
+### clear
+
+Clear the canvas manually.
+
+```javascript
+$('#wPaint').wPaint('clear');
+```
+
+
+### undo / redo
+
+We can also manually run an `undo` or `redo`.
+
+```javascript
+$('#wPaint').wPaint('undo');
+$('#wPaint').wPaint('redo');
+```
+
+
+## Extending
+
+With version 2.0 wPaint can now easily be extended by setting all or some of the following properties:
+
+```js
+// add menu
+$.fn.wPaint.menus.main = {
+ img: '/plugins/main/img/icons-menu-main.png',
+ items: {
+ undo: {
+ icon: 'generic',
+ title: 'Undo',
+ index: 0,
+ callback: function () { this.undo(); }
+ }
+}
+
+// extend cursors
+$.extend($.fn.wPaint.cursors, {
+ pencil: 'url("/plugins/main/img/cursor-pencil.png") 0 11.99, default',
+});
+
+// extend defaults
+$.extend($.fn.wPaint.defaults, {
+ mode: 'pencil', // set mode
+ lineWidth: '3', // starting line width
+ fillStyle: '#FFFFFF', // starting fill style
+ strokeStyle: '#FFFF00' // start stroke style
+});
+
+// extend functions
+$.fn.wPaint.extend({
+ undo: function () {
+ if (this.undoArray[this.undoCurrent - 1]) {
+ this._setUndo(--this.undoCurrent);
+ }
+
+ this._undoToggleIcons();
+ }
+});
+```
+
+
+### overriding
+
+When calling the `$.fn.wPaint.extend()` function the values for functions will not override the existing functions but just extend them with duck punching technique. This means the original funciton will always run followed by your extended function.
+
+This allows us to just string multiple `generate` or `init` functions together and not have to worry about overwriting any code.
+
+
+
+### menus
+
+The first menu appended will always automatically become the `primary` menu meaning it is the one displayed on init. All other menus will become `secondary` menus meaning they are toggled by icons.
+
+We can extend, modify or add items in the menu by updating the object we want. So for instance if we want to add a new icon to the main menu we could just do:
+
+```js
+$.fn.wPaint.menus.main.items.undo = {
+ // set properties here
+};
+```
+
+Likewise we can overwrite or add properties to an existing object. For instance below we modified the title and added the `after` property to change the position in which the `undo` icon will appear in the menu.
+
+```js
+$.fn.wPaint.menus.main.items.undo = {
+ title: 'Undo at your own risk',
+ after: 'clear'
+};
+```
+
+
+### icon properties
+
+Below is just a sample to list all possible icon properties. Note that the icon name such as `undo` is the `key` name used for CSS styling and internal naming.
+
+```js
+undo: {
+
+ // The icon sets the type of icon we want to generate
+ // below are the available types that come out of the box.
+ //
+ // generic: just runs a callback and nothing else
+ // activate: runs callback and activates (highlights)
+ // colorPicker: generates a color picker
+ // select: generates a select box (list)
+ // toggle: toggles on/off returns true or false
+ // menu: toggles secondary menu (icon/menu name must match)
+ icon: 'generic',
+
+ // Set a group for an icon turning it into a stacked
+ // group select (list). All icons with this group name will
+ // be appended to that select list. If not set the icon will
+ // just be standalone.
+ group: null,
+
+ // Set placement of icon in reference to another icon
+ after: 'clear',
+
+ // Title displayed on hover.
+ title: 'Undo',
+
+ // set an alternate image path to use for this icon
+ img: '/som/path.png',
+
+ // Index position in image file starting from 0
+ index: 0,
+
+ // a range of values to use for a select icon
+ range: [1, 2, 3, 4, 5],
+
+ // User range will set the value of the range as the
+ // css property based on the name of the icon. For instance
+ // if the icon is fontFamily that css property will get set.
+ useRange: true,
+
+ // The default value to set for this icon. This of course
+ // can be overridden using `set` calls on init.
+ value: 3,
+
+ // Callback when icon is clicked.
+ callback: function () { this.undo(); }
+}
+```
+
+If you want to create a new icon type you will need to extend wPaint to include processing for this new icon. A funciton in the form below should be written:
+
+```js
+_createIconType: function (item) {
+
+ // Get your started with a base icon.
+ var $icon = this._createIconBase(item);
+
+ // Return the icon with whatever functionality
+ // you want to add to it.
+ return $icon;
+}
+```
+
+
+### icon images
+
+Images for each plugin should be kept in one file and can be either specificed by the `img` value on the top level and can be overriden at the icon level. Each icon should also specify an index value as to the position of the icon in the image starting from 0. Icons should alll be the same size and dimensions should be set in the `size` theme.
+
+```js
+$.fn.wPaint.menus.main.items.undo = {
+ img: '/plugins/main/img/icons-menu-main.png',
+ items: {
+ undo: {
+ icon: 'generic',
+ title: 'Undo',
+ img: '/some/other/path.png'
+ index: 0,
+ callback: function () { this.undo(); }
+ }
+}
+```
+
+
+### cursors
+
+There is now a master `cursors` object used to store cursor references.
+
+$.extend($.fn.wPaint.cursors, {
+ pencil: 'url("/plugins/main/img/cursor-pencil.png") 0 11.99, default',
+});
+
+We can sepcify the cursor to use by calling `setCursor()` and passing the cursor name to use. Note that this is a set function and we can set the cursor at any time.
+
+```js
+$('#wPaint').wPaint('cursor', 'rocket');
+```
+
+Note that when you are setting the position of the cursor never set it to the exact dimension. For instance if the iamge is `12x12` and you want it's position to be `12` set it to `11.99`. This is do to some strange bug in Chrome which will not position the curosr if set exactly.
+
+
+## Thanks
+
+Thanks to everyone who has contribute code in the previous version and has showed interest in the plugin. Below is some thanks and attribution for code used in this plugin (if I left you out please let me know).
+
+* [Rounded corners and extending Canvas with new shapes](http://js-bits.blogspot.com/2010/07/canvas-rounded-corner-rectangles.html)
+* [Nice efficient algorithm for fill tool](http://www.williammalone.com/articles/html5-canvas-javascript-paint-bucket-tool)
+
+
+## Resources
+
+* [More jQuery plugins by Websanova](http://websanova.com/plugins)
+* [Websanova JavaScript Extensions Project](http://websanova.com/extensions)
+* [jQuery Plugin Development Boilerplate](http://wboiler.websanova.com)
+* [The Ultimate Guide to Writing jQuery Plugins](http://www.websanova.com/blog/jquery/the-ultimate-guide-to-writing-jquery-plugins)
+
+
+## License
+
+MIT licensed
+
+Copyright (C) 2011-2012 Websanova http://www.websanova.com
diff --git a/static/js/wpaint/bai.js b/static/js/wpaint/bai.js
new file mode 100644
index 0000000..6b436c1
--- /dev/null
+++ b/static/js/wpaint/bai.js
@@ -0,0 +1,23 @@
+function saveImg(image) {
+ var _this = this;
+ var url = document.getElementById('finish').href;
+
+ $.ajax({
+ type: 'POST',
+ url: '/oek_temp/upload.php',
+ data: {image: image},
+ success: function (resp) {
+ _this._displayStatus('Image saved successfully');
+ window.location.href = url;
+ }
+ });
+}
+
+$('#wPaint').wPaint({
+ path: '/static/js/wpaint/',
+ bg: '#ffffff',
+ menuOffsetLeft: -35,
+ menuOffsetTop: -50,
+ menuOrientation: 'horizontal',
+ saveImg: saveImg
+}); \ No newline at end of file
diff --git a/static/js/wpaint/demo/demo.css b/static/js/wpaint/demo/demo.css
new file mode 100644
index 0000000..ad8a418
--- /dev/null
+++ b/static/js/wpaint/demo/demo.css
@@ -0,0 +1,266 @@
+/*** layout ***/
+
+body, html {
+ font-family: verdana;
+ font-size: 12px;
+ line-height:20px;
+ color: #333;
+ background-color: #FEFEFE;
+ margin: 0;
+ text-rendering: optimizeLegibility;
+}
+a {
+ color: #3399FF;
+ text-decoration: none;
+}
+code {
+ padding: 1px 3px;
+ color: #D14;
+ background-color: #F7F7F9;
+ border: 1px solid #E1E1E8;
+ border-radius: 5px;
+}
+
+h2 {
+ display: inline-block;
+}
+
+.no-margin-top {
+ margin-top: 0px;
+}
+
+/*** header ***/
+
+header {
+ position: fixed;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 40px;
+ line-height: 40px;
+ background-color: #1B1B1B;
+ background-image: linear-gradient(to bottom, #222222, #111111);
+ background-repeat: repeat-x;
+ border-color: #252525;
+ box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
+ border-width: 0 0 1px;
+ color: #FFF;
+ font-size: 10px;
+ text-align: left;
+ vertical-align: middle;
+ z-index: 100;
+}
+#header-logo {
+ position: absolute;
+ display: block;
+ width: 94px;
+ height: 20px;
+ left: 10px;
+ top: 10px;
+ background-image: url('./img/websanova-logo-small-full-black.png');
+}
+#header-links {
+ display: none;
+ position: absolute;
+ width: 100%;
+ left: 0px;
+ top: 40px;
+}
+#header-links a {
+ display: block;
+ font-size: 9px;
+ font-weight: bold;
+ font-family: Verdana;
+ color: #FAFAFA;
+ text-transform: uppercase;
+ margin-left: 0px;
+ text-align: center;
+ background-color: #1B1B1B;
+ border-top: solid 1px #CACACA;
+ line-height: 14px;
+ padding: 10px;
+}
+#header-links a:hover {
+ color: #636363;
+}
+
+/*** menu ***/
+
+#header-menu-button {
+ position: absolute;
+ right: 6px;
+ top: 6px;
+ display: block;
+ color: #757575;
+ background-color: #e1e1e1;
+ background-repeat: repeat-x;
+ background-image: -moz-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: -ms-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: -webkit-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: -o-linear-gradient(top, #ebebeb, #e1e1e1);
+ background-image: linear-gradient(top, #ebebeb, #e1e1e1);
+ box-shadow: inset 0 0 8px 2px #c6c6c6, 0 1px 0 0 #f4f4f4;
+ border: none;
+ border-radius: 3px;
+ -webkit-border-radius: 3px;
+ padding: 6px 10px;
+ font-size: 11px;
+ line-height: 16px;
+ cursor: pointer;
+}
+
+/*** content ***/
+
+#plugin-name {
+ padding-bottom: 30px;
+ font-size: 24px;
+ border-bottom: solid #CACACA 1px;
+}
+#github-button {
+ display: block;
+ float: left;
+ margin-right: 2px;
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+ background-image: url('./img/addthis-github.png');
+}
+#addthis-toolbox {
+ position: absolute;
+ right: 15px;
+ top: 40px;
+}
+#content {
+ position: relative;
+ background: #FEFEFE;
+ max-width: 728px;
+ padding: 20px;
+ margin: 30px auto;
+}
+.content-box {
+ padding-left: 10px;
+}
+#content ul {
+ padding-left: 30px;
+}
+/*** footer ***/
+
+footer {
+ position: fixed;
+ left: 0px;
+ bottom: -1px;
+ width: 100%;
+ height: 40px;
+ line-height: 40px;
+ background-color: #1B1B1B;
+ background-image: linear-gradient(to bottom, #222222, #111111);
+ background-repeat: repeat-x;
+ border-color: #252525;
+ box-shadow: 10px 1px 10px rgba(0, 0, 0, 0.5);
+ border-width: 0 0 1px;
+ color: #FFF;
+ font-size: 10px;
+ text-align: left;
+ vertical-align: middle;
+ z-index: 100;
+}
+#footer-icons {
+ position: absolute;
+ right: 10px;
+ top: 0px;
+}
+#footer-icons a {
+ display: inline-block;
+ *display: inline;
+ zoom: 1;
+ width: 17px;
+ height: 17px;
+ margin: 12px 0 0 10px;
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+#linkedin-icon { background-image: url('./img/linkedin-icon.png'); width: 18px; }
+#stumbleupon-icon { background-image: url('./img/stumbleupon-icon.png'); }
+#googleplus-icon { background-image: url('./img/googleplus-icon.png'); }
+#youtube-icon { background-image: url('./img/youtube-icon.png'); width: 17px; height: 18px; }
+#facebook-icon { background-image: url('./img/facebook-icon.png'); width: 8px; }
+#twitter-icon { background-image: url('./img/twitter-icon.png'); width: 20px; }
+#github-icon { background-image: url('./img/github-icon.png'); width: 20px; }
+#rss-icon { background-image: url('./img/rss-icon.png'); }
+
+
+/*** media ***/
+
+@media screen and (min-width: 600px) {
+ #header-logo {
+ left: 50px;
+ }
+ #footer-icons {
+ left: auto;
+ right: 50px;
+ }
+ #header-links {
+ display: block !important;
+ width: auto;
+ top: 0px;
+ left: auto;
+ right: 50px;
+ }
+ #header-links a {
+ display: inline;
+ font-size: 10px;
+ margin-left: 20px;
+ text-align: left;
+ background-color: none;
+ border-top: 0px;
+ margin-left: 10px;
+ line-height: inherit;
+ padding: 0px;
+ }
+ #header-menu-button {
+ display: none;
+ }
+ #plugin-name {
+ font-size: 30px;
+ }
+ #addthis-toolbox {
+ top: 44px;
+ }
+}
+
+/*** ads ***/
+
+.websanova-plugins-page-horizontal-responsive { display:block; margin:0 auto; width: 320px; height: 50px; }
+@media(min-width: 520px) { .websanova-plugins-page-horizontal-responsive { width: 468px; height: 60px; } }
+@media(min-width: 800px) { .websanova-plugins-page-horizontal-responsive { width: 728px; height: 90px; } }
+
+.adsblock {
+ position: relative;
+ margin: 0 auto;
+}
+.ads2block {
+ margin-top: 20px;
+}
+.adsblock-mobile-banner {
+ width: 320px;
+ height: 50px;
+}
+.adsblock-banner {
+ display: none;
+ width: 468px;
+ height: 60px;
+}
+.adsblock-leaderboard {
+ display: none;
+ width: 728px;
+ height: 90px;
+}
+@media (min-width:520px) {
+ .adsblock-mobile-banner { display: none; }
+ .adsblock-banner { display: block; }
+}
+@media (min-width:800px) {
+ .adsblock-mobile-banner { display: none; }
+ .adsblock-banner { display: none; }
+ .adsblock-leaderboard { display: block; }
+} \ No newline at end of file
diff --git a/static/js/wpaint/demo/img/facebook-icon.png b/static/js/wpaint/demo/img/facebook-icon.png
new file mode 100644
index 0000000..dfb0f3e
--- /dev/null
+++ b/static/js/wpaint/demo/img/facebook-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/favicon.ico b/static/js/wpaint/demo/img/favicon.ico
new file mode 100644
index 0000000..9bd6326
--- /dev/null
+++ b/static/js/wpaint/demo/img/favicon.ico
Binary files differ
diff --git a/static/js/wpaint/demo/img/forkme_right_darkblue.png b/static/js/wpaint/demo/img/forkme_right_darkblue.png
new file mode 100644
index 0000000..146ef8a
--- /dev/null
+++ b/static/js/wpaint/demo/img/forkme_right_darkblue.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/github-icon.png b/static/js/wpaint/demo/img/github-icon.png
new file mode 100644
index 0000000..a28067c
--- /dev/null
+++ b/static/js/wpaint/demo/img/github-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/googleplus-icon.png b/static/js/wpaint/demo/img/googleplus-icon.png
new file mode 100644
index 0000000..6567f6e
--- /dev/null
+++ b/static/js/wpaint/demo/img/googleplus-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/linkedin-icon.png b/static/js/wpaint/demo/img/linkedin-icon.png
new file mode 100644
index 0000000..a2628e7
--- /dev/null
+++ b/static/js/wpaint/demo/img/linkedin-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/rss-icon.png b/static/js/wpaint/demo/img/rss-icon.png
new file mode 100644
index 0000000..faae141
--- /dev/null
+++ b/static/js/wpaint/demo/img/rss-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/stumbleupon-icon.png b/static/js/wpaint/demo/img/stumbleupon-icon.png
new file mode 100644
index 0000000..5e82ea8
--- /dev/null
+++ b/static/js/wpaint/demo/img/stumbleupon-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/twitter-icon.png b/static/js/wpaint/demo/img/twitter-icon.png
new file mode 100644
index 0000000..499ca0c
--- /dev/null
+++ b/static/js/wpaint/demo/img/twitter-icon.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/websanova-logo-small-full-black.png b/static/js/wpaint/demo/img/websanova-logo-small-full-black.png
new file mode 100644
index 0000000..a5bd0f6
--- /dev/null
+++ b/static/js/wpaint/demo/img/websanova-logo-small-full-black.png
Binary files differ
diff --git a/static/js/wpaint/demo/img/youtube-icon.png b/static/js/wpaint/demo/img/youtube-icon.png
new file mode 100644
index 0000000..e697406
--- /dev/null
+++ b/static/js/wpaint/demo/img/youtube-icon.png
Binary files differ
diff --git a/static/js/wpaint/gruntfile.js b/static/js/wpaint/gruntfile.js
new file mode 100644
index 0000000..4e1eb06
--- /dev/null
+++ b/static/js/wpaint/gruntfile.js
@@ -0,0 +1,90 @@
+module.exports = function(grunt) {
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ jshint: {
+ options: {
+ bitwise: true,
+ camelcase: true,
+ indent: 2,
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ unused: true,
+ boss: true,
+ eqnull: true,
+ white: true,
+ validthis: true,
+ quotmark: 'single',
+ globals: {
+ 'window': true,
+ 'jQuery': true,
+ 'document': true,
+ 'Image': true,
+ 'setTimeout': true,
+ 'clearTimeout': true,
+ 'event': true,
+ 'CanvasRenderingContext2D': true
+ }
+ },
+ files: {
+ src: ['./plugins/**/src/wPaint-*.js', './src/*.js']
+ }
+ },
+ uglify: {
+ options: {
+ banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %> */'
+ },
+ my_target: {
+ files: {
+ './wPaint.min.js': ['./src/wPaint.js', './src/wPaint.utils.js'],
+ './plugins/main/wPaint.menu.main.min.js': ['./plugins/main/src/wPaint.menu.main.js', './plugins/main/src/fillArea.min.js'],
+ './plugins/text/wPaint.menu.text.min.js': ['./plugins/text/src/wPaint.menu.text.js'],
+ './plugins/shapes/wPaint.menu.main.shapes.min.js': ['./plugins/shapes/src/wPaint.menu.main.shapes.js', './plugins/shapes/src/shapes.min.js'],
+ './plugins/file/wPaint.menu.main.file.min.js': ['./plugins/file/src/wPaint.menu.main.file.js']
+ }
+ }
+ },
+ stylus: {
+ compile: {
+ options: {
+ import: ['nib', '../lib/mixins'],
+ },
+ files: {
+ './wPaint.min.css': './src/wPaint.css'
+ }
+ }
+ },
+ concat: {
+ basic_and_extras: {
+ files: {
+ 'wPaint-min.js': ['./lib/wColorPicker.min.js', './wPaint.min.js'],
+ 'wPaint-min.css': ['./lib/wColorPicker.min.css', './wPaint.min.css'],
+ },
+ }
+ },
+ watch: {
+ files: [
+ './src/wPaint.css',
+ './src/wPaint.js',
+ './plugins/file/src/wPaint.menu.main.js',
+ './plugins/file/src/wPaint.menu.text.js',
+ './plugins/file/src/wPaint.menu.main.shapes.js',
+ './plugins/file/src/wPaint.menu.main.file.js'
+ ],
+ tasks: ['uglify']
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-contrib-watch');
+ grunt.loadNpmTasks('grunt-contrib-stylus');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-concat');
+
+ grunt.registerTask('default', ['jshint', 'stylus', 'uglify']);
+}; \ No newline at end of file
diff --git a/static/js/wpaint/index.html b/static/js/wpaint/index.html
new file mode 100644
index 0000000..391261e
--- /dev/null
+++ b/static/js/wpaint/index.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width" />
+
+ <title>Websanova :: wPaint</title>
+
+ <!-- filestart -->
+ <link rel="icon" type="image/vnd.microsoft.icon" href="./demo/img/favicon.ico" />
+ <link rel="Stylesheet" type="text/css" href="./demo/demo.css" />
+ <script type="text/javascript" src="./lib/jquery.1.10.2.min.js"></script>
+ <!-- fileend -->
+</head>
+<body>
+ <!-- headstart -->
+ <header>
+ <a id="header-logo" href="http://websanova.com"></a>
+
+ <div id="header-links">
+ <a href="http://websanova.com">Blog</a>
+ <a href="http://websanova.com/plugins">Plugins</a>
+ <a href="http://websanova.com/extensions">Extensions</a>
+ <a href="http://websanova.com/services">Services</a>
+ </div>
+ </header>
+ <!-- headend -->
+
+ <div id="content">
+ <h1 id="plugin-name">wPaint.js</h1>
+
+ <div class="content-box">
+ <!-- jQuery UI -->
+ <script type="text/javascript" src="./lib/jquery.ui.core.1.10.3.min.js"></script>
+ <script type="text/javascript" src="./lib/jquery.ui.widget.1.10.3.min.js"></script>
+ <script type="text/javascript" src="./lib/jquery.ui.mouse.1.10.3.min.js"></script>
+ <script type="text/javascript" src="./lib/jquery.ui.draggable.1.10.3.min.js"></script>
+
+ <!-- wColorPicker -->
+ <link rel="Stylesheet" type="text/css" href="./lib/wColorPicker.min.css" />
+ <script type="text/javascript" src="./lib/wColorPicker.min.js"></script>
+
+ <!-- wPaint -->
+ <link rel="Stylesheet" type="text/css" href="./wPaint.min.css" />
+ <script type="text/javascript" src="./wPaint.min.js"></script>
+ <script type="text/javascript" src="./plugins/main/wPaint.menu.main.min.js"></script>
+ <script type="text/javascript" src="./plugins/text/wPaint.menu.text.min.js"></script>
+ <script type="text/javascript" src="./plugins/shapes/wPaint.menu.main.shapes.min.js"></script>
+ <script type="text/javascript" src="./plugins/file/wPaint.menu.main.file.min.js"></script>
+
+ <div id="wPaint" style="position:relative; width:500px; height:200px; background-color:#7a7a7a; margin:70px auto 20px auto;"></div>
+
+ <center style="margin-bottom: 50px;">
+ <input type="button" value="toggle menu" onclick="console.log($('#wPaint').wPaint('menuOrientation')); $('#wPaint').wPaint('menuOrientation', $('#wPaint').wPaint('menuOrientation') === 'vertical' ? 'horizontal' : 'vertical');"/>
+ </center>
+
+ <center id="wPaint-img"></center>
+
+ <script type="text/javascript">
+ var images = [
+ '/test/uploads/wPaint.png',
+ ];
+
+ function saveImg(image) {
+ var _this = this;
+
+ $.ajax({
+ type: 'POST',
+ url: '/test/upload.php',
+ data: {image: image},
+ success: function (resp) {
+
+ // internal function for displaying status messages in the canvas
+ _this._displayStatus('Image saved successfully');
+
+ // doesn't have to be json, can be anything
+ // returned from server after upload as long
+ // as it contains the path to the image url
+ // or a base64 encoded png, either will work
+ resp = $.parseJSON(resp);
+
+ // update images array / object or whatever
+ // is being used to keep track of the images
+ // can store path or base64 here (but path is better since it's much smaller)
+ images.push(resp.img);
+
+ // do something with the image
+ $('#wPaint-img').attr('src', image);
+ }
+ });
+ }
+
+ function loadImgBg () {
+
+ // internal function for displaying background images modal
+ // where images is an array of images (base64 or url path)
+ // NOTE: that if you can't see the bg image changing it's probably
+ // becasue the foregroud image is not transparent.
+ this._showFileModal('bg', images);
+ }
+
+ function loadImgFg () {
+
+ // internal function for displaying foreground images modal
+ // where images is an array of images (base64 or url path)
+ this._showFileModal('fg', images);
+ }
+
+ // init wPaint
+ $('#wPaint').wPaint({
+ menuOffsetLeft: -35,
+ menuOffsetTop: -50,
+ saveImg: saveImg,
+ loadImgBg: loadImgBg,
+ loadImgFg: loadImgFg
+ });
+ </script>
+ </div>
+ </div>
+
+ <!-- footstart -->
+ <footer>
+ <div id="footer-icons">
+ <!--a id="youtube-icon" href="http://websanova.com/youtube" target="_blank"></a-->
+ <a id="stumbleupon-icon" href="http://websanova.com/stumbleupon" target="_blank"></a>
+ <a id="linkedin-icon" href="http://websanova.com/linkedin" target="_blank"></a>
+ <a id="facebook-icon" href="http://websanova.com/facebook" target="_blank"></a>
+ <a id="googleplus-icon" href="http://websanova.com/googleplus" target="_blank"></a>
+ <a id="twitter-icon" href="http://websanova.com/twitter" target="_blank"></a>
+ <a id="github-icon" href="http://websanova.com/github" target="_blank"></a>
+ <a id="rss-icon" href="http://websanova.com/feed" target="_blank"></a>
+ </div>
+ </footer>
+ <!-- footend -->
+</body>
+</html> \ No newline at end of file
diff --git a/static/js/wpaint/lib/jquery.1.10.2.min.js b/static/js/wpaint/lib/jquery.1.10.2.min.js
new file mode 100644
index 0000000..76d21a4
--- /dev/null
+++ b/static/js/wpaint/lib/jquery.1.10.2.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-1.10.2.min.map
+*/
+(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
+}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
+u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window); \ No newline at end of file
diff --git a/static/js/wpaint/lib/jquery.ui.core.1.10.3.min.js b/static/js/wpaint/lib/jquery.ui.core.1.10.3.min.js
new file mode 100644
index 0000000..bf1129a
--- /dev/null
+++ b/static/js/wpaint/lib/jquery.ui.core.1.10.3.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-06-12
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e,t){function i(t,i){var a,n,r,o=t.nodeName.toLowerCase();return"area"===o?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&s(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var a=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var s,a,n=e(this[0]);n.length&&n[0]!==document;){if(s=n.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(a=parseInt(n.css("zIndex"),10),!isNaN(a)&&0!==a))return a;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++a)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var s=e.attr(t,"tabindex"),a=isNaN(s);return(a||s>=0)&&i(t,!a)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(i,s){function a(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===s?["Left","Right"]:["Top","Bottom"],r=s.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+s]=function(i){return i===t?o["inner"+s].call(this):this.each(function(){e(this).css(r,a(this,i)+"px")})},e.fn["outer"+s]=function(t,i){return"number"!=typeof t?o["outer"+s].call(this,t):this.each(function(){e(this).css(r,a(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i){var s,a=e.plugins[t];if(a&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(s=0;a.length>s;s++)e.options[a[s][0]]&&a[s][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",a=!1;return t[s]>0?!0:(t[s]=1,a=t[s]>0,t[s]=0,a)}})})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/lib/jquery.ui.draggable.1.10.3.min.js b/static/js/wpaint/lib/jquery.ui.draggable.1.10.3.min.js
new file mode 100644
index 0000000..3b7b149
--- /dev/null
+++ b/static/js/wpaint/lib/jquery.ui.draggable.1.10.3.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-06-12
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){e.widget("ui.draggable",e.ui.mouse,{version:"1.10.3",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"!==this.options.helper||/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var i=this.options;return this.helper||i.disabled||e(t.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(t),this.handle?(e(i.iframeFix===!0?"iframe":i.iframeFix).each(function(){e("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var i=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offsetParent=this.helper.offsetParent(),this.offsetParentCssPosition=this.offsetParent.css("position"),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},this.offset.scroll=!1,e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,i){if("fixed"===this.offsetParentCssPosition&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",t,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.options.axis&&"y"===this.options.axis||(this.helper[0].style.left=this.position.left+"px"),this.options.axis&&"x"===this.options.axis||(this.helper[0].style.top=this.position.top+"px"),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var i=this,s=!1;return e.ui.ddmanager&&!this.options.dropBehaviour&&(s=e.ui.ddmanager.drop(this,t)),this.dropped&&(s=this.dropped,this.dropped=!1),"original"!==this.options.helper||e.contains(this.element[0].ownerDocument,this.element[0])?("invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",t)!==!1&&i._clear()}):this._trigger("stop",t)!==!1&&this._clear(),!1):!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){return this.options.handle?!!e(t.target).closest(this.element.find(this.options.handle)).length:!0},_createHelper:function(t){var i=this.options,s=e.isFunction(i.helper)?e(i.helper.apply(this.element[0],[t])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return s.parents("body").length||s.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s[0]===this.element[0]||/(fixed|absolute)/.test(s.css("position"))||s.css("position","absolute"),s},_adjustOffsetFromHelper:function(t){"string"==typeof t&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){var t=this.offsetParent.offset();return"absolute"===this.cssPosition&&this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop()),(this.offsetParent[0]===document.body||this.offsetParent[0].tagName&&"html"===this.offsetParent[0].tagName.toLowerCase()&&e.ui.ie)&&(t={top:0,left:0}),{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"===this.cssPosition){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t,i,s,n=this.options;return n.containment?"window"===n.containment?(this.containment=[e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,e(window).scrollLeft()+e(window).width()-this.helperProportions.width-this.margins.left,e(window).scrollTop()+(e(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):"document"===n.containment?(this.containment=[0,0,e(document).width()-this.helperProportions.width-this.margins.left,(e(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],undefined):n.containment.constructor===Array?(this.containment=n.containment,undefined):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=e(n.containment),s=i[0],s&&(t="hidden"!==i.css("overflow"),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(t?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(t?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=i),undefined):(this.containment=null,undefined)},_convertPositionTo:function(t,i){i||(i=this.position);var s="absolute"===t?1:-1,n="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent;return this.offset.scroll||(this.offset.scroll={top:n.scrollTop(),left:n.scrollLeft()}),{top:i.top+this.offset.relative.top*s+this.offset.parent.top*s-("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top)*s,left:i.left+this.offset.relative.left*s+this.offset.parent.left*s-("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)*s}},_generatePosition:function(t){var i,s,n,a,o=this.options,r="absolute"!==this.cssPosition||this.scrollParent[0]!==document&&e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,h=t.pageX,l=t.pageY;return this.offset.scroll||(this.offset.scroll={top:r.scrollTop(),left:r.scrollLeft()}),this.originalPosition&&(this.containment&&(this.relative_container?(s=this.relative_container.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.left<i[0]&&(h=i[0]+this.offset.click.left),t.pageY-this.offset.click.top<i[1]&&(l=i[1]+this.offset.click.top),t.pageX-this.offset.click.left>i[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1},_trigger:function(t,i,s){return s=s||this._uiHash(),e.ui.plugin.call(this,t,[i,s]),"drag"===t&&(this.positionAbs=this._convertPositionTo("absolute")),e.Widget.prototype._trigger.call(this,t,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),e.ui.plugin.add("draggable","connectToSortable",{start:function(t,i){var s=e(this).data("ui-draggable"),n=s.options,a=e.extend({},i,{item:s.element});s.sortables=[],e(n.connectToSortable).each(function(){var i=e.data(this,"ui-sortable");i&&!i.options.disabled&&(s.sortables.push({instance:i,shouldRevert:i.options.revert}),i.refreshPositions(),i._trigger("activate",t,a))})},stop:function(t,i){var s=e(this).data("ui-draggable"),n=e.extend({},i,{item:s.element});e.each(s.sortables,function(){this.instance.isOver?(this.instance.isOver=0,s.cancelHelperRemoval=!0,this.instance.cancelHelperRemoval=!1,this.shouldRevert&&(this.instance.options.revert=this.shouldRevert),this.instance._mouseStop(t),this.instance.options.helper=this.instance.options._helper,"original"===s.options.helper&&this.instance.currentItem.css({top:"auto",left:"auto"})):(this.instance.cancelHelperRemoval=!1,this.instance._trigger("deactivate",t,n))})},drag:function(t,i){var s=e(this).data("ui-draggable"),n=this;e.each(s.sortables,function(){var a=!1,o=this;this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this.instance._intersectsWith(this.instance.containerCache)&&(a=!0,e.each(s.sortables,function(){return this.instance.positionAbs=s.positionAbs,this.instance.helperProportions=s.helperProportions,this.instance.offset.click=s.offset.click,this!==o&&this.instance._intersectsWith(this.instance.containerCache)&&e.contains(o.instance.element[0],this.instance.element[0])&&(a=!1),a})),a?(this.instance.isOver||(this.instance.isOver=1,this.instance.currentItem=e(n).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",!0),this.instance.options._helper=this.instance.options.helper,this.instance.options.helper=function(){return i.helper[0]},t.target=this.instance.currentItem[0],this.instance._mouseCapture(t,!0),this.instance._mouseStart(t,!0,!0),this.instance.offset.click.top=s.offset.click.top,this.instance.offset.click.left=s.offset.click.left,this.instance.offset.parent.left-=s.offset.parent.left-this.instance.offset.parent.left,this.instance.offset.parent.top-=s.offset.parent.top-this.instance.offset.parent.top,s._trigger("toSortable",t),s.dropped=this.instance.element,s.currentItem=s.element,this.instance.fromOutside=s),this.instance.currentItem&&this.instance._mouseDrag(t)):this.instance.isOver&&(this.instance.isOver=0,this.instance.cancelHelperRemoval=!0,this.instance.options.revert=!1,this.instance._trigger("out",t,this.instance._uiHash(this.instance)),this.instance._mouseStop(t,!0),this.instance.options.helper=this.instance.options._helper,this.instance.currentItem.remove(),this.instance.placeholder&&this.instance.placeholder.remove(),s._trigger("fromSortable",t),s.dropped=!1)})}}),e.ui.plugin.add("draggable","cursor",{start:function(){var t=e("body"),i=e(this).data("ui-draggable").options;t.css("cursor")&&(i._cursor=t.css("cursor")),t.css("cursor",i.cursor)},stop:function(){var t=e(this).data("ui-draggable").options;t._cursor&&e("body").css("cursor",t._cursor)}}),e.ui.plugin.add("draggable","opacity",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("opacity")&&(n._opacity=s.css("opacity")),s.css("opacity",n.opacity)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._opacity&&e(i.helper).css("opacity",s._opacity)}}),e.ui.plugin.add("draggable","scroll",{start:function(){var t=e(this).data("ui-draggable");t.scrollParent[0]!==document&&"HTML"!==t.scrollParent[0].tagName&&(t.overflowOffset=t.scrollParent.offset())},drag:function(t){var i=e(this).data("ui-draggable"),s=i.options,n=!1;i.scrollParent[0]!==document&&"HTML"!==i.scrollParent[0].tagName?(s.axis&&"x"===s.axis||(i.overflowOffset.top+i.scrollParent[0].offsetHeight-t.pageY<s.scrollSensitivity?i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop+s.scrollSpeed:t.pageY-i.overflowOffset.top<s.scrollSensitivity&&(i.scrollParent[0].scrollTop=n=i.scrollParent[0].scrollTop-s.scrollSpeed)),s.axis&&"y"===s.axis||(i.overflowOffset.left+i.scrollParent[0].offsetWidth-t.pageX<s.scrollSensitivity?i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft+s.scrollSpeed:t.pageX-i.overflowOffset.left<s.scrollSensitivity&&(i.scrollParent[0].scrollLeft=n=i.scrollParent[0].scrollLeft-s.scrollSpeed))):(s.axis&&"x"===s.axis||(t.pageY-e(document).scrollTop()<s.scrollSensitivity?n=e(document).scrollTop(e(document).scrollTop()-s.scrollSpeed):e(window).height()-(t.pageY-e(document).scrollTop())<s.scrollSensitivity&&(n=e(document).scrollTop(e(document).scrollTop()+s.scrollSpeed))),s.axis&&"y"===s.axis||(t.pageX-e(document).scrollLeft()<s.scrollSensitivity?n=e(document).scrollLeft(e(document).scrollLeft()-s.scrollSpeed):e(window).width()-(t.pageX-e(document).scrollLeft())<s.scrollSensitivity&&(n=e(document).scrollLeft(e(document).scrollLeft()+s.scrollSpeed)))),n!==!1&&e.ui.ddmanager&&!s.dropBehaviour&&e.ui.ddmanager.prepareOffsets(i,t)}}),e.ui.plugin.add("draggable","snap",{start:function(){var t=e(this).data("ui-draggable"),i=t.options;t.snapElements=[],e(i.snap.constructor!==String?i.snap.items||":data(ui-draggable)":i.snap).each(function(){var i=e(this),s=i.offset();this!==t.element[0]&&t.snapElements.push({item:this,width:i.outerWidth(),height:i.outerHeight(),top:s.top,left:s.left})})},drag:function(t,i){var s,n,a,o,r,h,l,u,c,d,p=e(this).data("ui-draggable"),f=p.options,m=f.snapTolerance,g=i.offset.left,v=g+p.helperProportions.width,b=i.offset.top,y=b+p.helperProportions.height;for(c=p.snapElements.length-1;c>=0;c--)r=p.snapElements[c].left,h=r+p.snapElements[c].width,l=p.snapElements[c].top,u=l+p.snapElements[c].height,r-m>v||g>h+m||l-m>y||b>u+m||!e.contains(p.snapElements[c].item.ownerDocument,p.snapElements[c].item)?(p.snapElements[c].snapping&&p.options.snap.release&&p.options.snap.release.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=!1):("inner"!==f.snapMode&&(s=m>=Math.abs(l-y),n=m>=Math.abs(u-b),a=m>=Math.abs(r-v),o=m>=Math.abs(h-g),s&&(i.position.top=p._convertPositionTo("relative",{top:l-p.helperProportions.height,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r-p.helperProportions.width}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h}).left-p.margins.left)),d=s||n||a||o,"outer"!==f.snapMode&&(s=m>=Math.abs(l-b),n=m>=Math.abs(u-y),a=m>=Math.abs(r-g),o=m>=Math.abs(h-v),s&&(i.position.top=p._convertPositionTo("relative",{top:l,left:0}).top-p.margins.top),n&&(i.position.top=p._convertPositionTo("relative",{top:u-p.helperProportions.height,left:0}).top-p.margins.top),a&&(i.position.left=p._convertPositionTo("relative",{top:0,left:r}).left-p.margins.left),o&&(i.position.left=p._convertPositionTo("relative",{top:0,left:h-p.helperProportions.width}).left-p.margins.left)),!p.snapElements[c].snapping&&(s||n||a||o||d)&&p.options.snap.snap&&p.options.snap.snap.call(p.element,t,e.extend(p._uiHash(),{snapItem:p.snapElements[c].item})),p.snapElements[c].snapping=s||n||a||o||d)}}),e.ui.plugin.add("draggable","stack",{start:function(){var t,i=this.data("ui-draggable").options,s=e.makeArray(e(i.stack)).sort(function(t,i){return(parseInt(e(t).css("zIndex"),10)||0)-(parseInt(e(i).css("zIndex"),10)||0)});s.length&&(t=parseInt(e(s[0]).css("zIndex"),10)||0,e(s).each(function(i){e(this).css("zIndex",t+i)}),this.css("zIndex",t+s.length))}}),e.ui.plugin.add("draggable","zIndex",{start:function(t,i){var s=e(i.helper),n=e(this).data("ui-draggable").options;s.css("zIndex")&&(n._zIndex=s.css("zIndex")),s.css("zIndex",n.zIndex)},stop:function(t,i){var s=e(this).data("ui-draggable").options;s._zIndex&&e(i.helper).css("zIndex",s._zIndex)}})})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/lib/jquery.ui.mouse.1.10.3.min.js b/static/js/wpaint/lib/jquery.ui.mouse.1.10.3.min.js
new file mode 100644
index 0000000..82e3367
--- /dev/null
+++ b/static/js/wpaint/lib/jquery.ui.mouse.1.10.3.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-06-12
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.3",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/lib/jquery.ui.widget.1.10.3.min.js b/static/js/wpaint/lib/jquery.ui.widget.1.10.3.min.js
new file mode 100644
index 0000000..5f7a7c1
--- /dev/null
+++ b/static/js/wpaint/lib/jquery.ui.widget.1.10.3.min.js
@@ -0,0 +1,4 @@
+/*! jQuery UI - v1.10.3 - 2013-06-12
+* http://jqueryui.com
+* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
+(function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/lib/mixins.styl b/static/js/wpaint/lib/mixins.styl
new file mode 100644
index 0000000..b92debe
--- /dev/null
+++ b/static/js/wpaint/lib/mixins.styl
@@ -0,0 +1,7 @@
+display(type)
+ if type == 'inline-block'
+ display: inline-block;
+ *display: inline;
+ zoom: 1;
+ else
+ display: type; \ No newline at end of file
diff --git a/static/js/wpaint/lib/wColorPicker.min.css b/static/js/wpaint/lib/wColorPicker.min.css
new file mode 100644
index 0000000..9c39b88
--- /dev/null
+++ b/static/js/wpaint/lib/wColorPicker.min.css
@@ -0,0 +1,42 @@
+.wColorPicker{position:relative;display:inline-block;*display:inline;zoom:1;line-height:0;font-size:0;cursor:default}
+.wColorPicker-bg{position:absolute;left:0;top:0;width:100%;height:100%}
+.wColorPicker-holder{position:relative;display:inline-block;*display:inline;zoom:1;overflow:hidden}
+.wColorPicker-palettes-holder{position:relative;display:inline-block;*display:inline;zoom:1}
+.wColorPicker-zindex{z-index:1000}
+.wColorPicker-palette{position:relative;display:inline-block;*display:inline;zoom:1;margin:0 10px 10px 0}
+.wColorPicker-palette-none,.wColorPicker-palette-simple{margin-left:10px}
+.wColorPicker-palette-color{display:inline-block;*display:inline;zoom:1;vertical-align:middle;width:10px;height:10px;border-right:solid 1px;border-bottom:solid 1px;cursor:pointer}
+.wColorPicker-palette-color-left{border-left:solid 1px}
+.wColorPicker-palette-color-top{border-top:solid 1px}
+.wColorPicker-color-target{position:relative;display:inline-block;*display:inline;zoom:1;vertical-align:middle;width:40px;height:16px;border:solid 1px}
+.wColorPicker-custom-input{position:relative;display:inline-block;*display:inline;zoom:1;vertical-align:middle;width:70px;height:16px;line-height:16px;font-size:9px;font-family:verdana;padding:0 2px;border:solid 1px}
+.wColorPicker-color-target,.wColorPicker-custom-input{margin:10px 10px 10px 0}
+.wColorPicker-dropper{position:relative;display:inline-block;*display:inline;zoom:1;vertical-align:middle;width:16px;height:16px;border:solid 1px;cursor:pointer}
+.wColorPicker-button{position:relative;-webkit-border-radius:5px;border-radius:5px;border:solid #cacaca 1px;padding:1px}
+.wColorPicker-button-color{position:relative;-webkit-border-radius:5px;border-radius:5px}
+.wColorPicker-holder{border:solid 1px}
+.wColorPicker-bg,.wColorPicker-holder{-webkit-border-radius:5px;border-radius:5px}
+.wColorPicker-bg{-webkit-box-shadow:inset 2px 2px 3px #fff,1px 1px 2px #555;box-shadow:inset 2px 2px 3px #fff,1px 1px 2px #555}
+.wColorPicker-custom-input{opacity:.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50)}
+.wColorPicker-dropper{opacity:.6;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=60)";filter:alpha(opacity=60);-webkit-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 1px 1px 2px #fff,0 0 1px #777;box-shadow:inset 1px 1px 2px #fff,0 0 1px #777;background-color:#cacaca;background:no-repeat center center url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAYAAABWdVznAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABZ0RVh0Q3JlYXRpb24gVGltZQAwOC8wOS8xM9AohnYAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAA4ElEQVQokYXSMUpDARCE4e/FBCEggoVH0BtY2bsiiIWIipVHsLaOYCcWVtpYSBBEsNnO9qGFR/AKVhISNRa+SJDkudWw/DMwyxbD4dB/ExEnWMFBUWeIiAVs4RxtPDdr4DUcY7Va9fA01YAzLFd6gKPMvGhMSd/EKR6r1QsuofkHLLCDr8y8iohPLKKTmX34LR0RLeyij3uso4GHzByMQhtj8B56mdmt4HZm3o3DMFOWZYGogJuI2MZ8Zl5P6tfEHFroRsQ+ZjERHhkOK72Bd9xm5ked4RVLfk74lpm1v/INodZOOpic3qMAAAAASUVORK5CYII=")}
+.wColorPicker-theme-classic .wColorPicker-dropper,.wColorPicker-theme-classic .wColorPicker-custom-input,.wColorPicker-theme-classic .wColorPicker-color-target,.wColorPicker-theme-classic .wColorPicker-palette-color{border-color:#3a3a3a}
+.wColorPicker-theme-classic .wColorPicker-holder{border-color:#bababa}
+.wColorPicker-theme-classic .wColorPicker-bg{background-color:#aaa}
+.wColorPicker-theme-black .wColorPicker-dropper,.wColorPicker-theme-black .wColorPicker-color-target,.wColorPicker-theme-black .wColorPicker-color-input,.wColorPicker-theme-black .wColorPicker-palette-color{border-color:#3f3f3f}
+.wColorPicker-theme-black .wColorPicker-holder{border-color:#7f7f7f}
+.wColorPicker-theme-black .wColorPicker-bg{background-color:#363636}
+.wColorPicker-theme-blue .wColorPicker-dropper,.wColorPicker-theme-blue .wColorPicker-color-target,.wColorPicker-theme-blue .wColorPicker-color-input,.wColorPicker-theme-blue .wColorPicker-palette-color{border-color:#002f4d}
+.wColorPicker-theme-blue .wColorPicker-holder{border-color:#49afcd}
+.wColorPicker-theme-blue .wColorPicker-bg{background-color:#2f96b4}
+.wColorPicker-theme-red .wColorPicker-dropper,.wColorPicker-theme-red .wColorPicker-color-target,.wColorPicker-theme-red .wColorPicker-color-input,.wColorPicker-theme-red .wColorPicker-palette-color{border-color:#8a0f09}
+.wColorPicker-theme-red .wColorPicker-holder{border-color:#da4f49}
+.wColorPicker-theme-red .wColorPicker-bg{background-color:#bd362f}
+.wColorPicker-theme-green .wColorPicker-dropper,.wColorPicker-theme-green .wColorPicker-color-target,.wColorPicker-theme-green .wColorPicker-color-input,.wColorPicker-theme-green .wColorPicker-palette-color{border-color:#0b670b}
+.wColorPicker-theme-green .wColorPicker-holder{border-color:#5bb75b}
+.wColorPicker-theme-green .wColorPicker-bg{background-color:#51a351}
+.wColorPicker-theme-orange .wColorPicker-dropper,.wColorPicker-theme-orange .wColorPicker-color-target,.wColorPicker-theme-orange .wColorPicker-color-input,.wColorPicker-theme-orange .wColorPicker-palette-color{border-color:#9a5700}
+.wColorPicker-theme-orange .wColorPicker-holder{border-color:#faa732}
+.wColorPicker-theme-orange .wColorPicker-bg{background-color:#f89406}
+.wColorPicker-palette-color.active{border-color:#f00}
+.wColorPicker-palette-color.active-right{border-right-color:#f00}
+.wColorPicker-palette-color.active-bottom{border-bottom-color:#f00}
diff --git a/static/js/wpaint/lib/wColorPicker.min.js b/static/js/wpaint/lib/wColorPicker.min.js
new file mode 100644
index 0000000..cb515e6
--- /dev/null
+++ b/static/js/wpaint/lib/wColorPicker.min.js
@@ -0,0 +1,2 @@
+/*! rgbHex - v1.1.2 - 2013-09-27 */window.rgbHex=function(){function a(a){return!isNaN(parseFloat(a))&&isFinite(a)}function b(a){return a.replace(/^\s+|\s+$/g,"")}function c(c){return c=b(c),a(c)&&c>=0&&255>=c}function d(a){return/^[0-9a-f]{3}$|^[0-9a-f]{6}$/i.test(b(a))}function e(a){return a=parseInt(a,10).toString(16),1===a.length?"0"+a:a}function f(a){return parseInt(a,16).toString()}function g(b){return b=b.split(","),(3===b.length||4===b.length)&&c(b[0])&&c(b[1])&&c(b[2])?4!==b.length||a(b[3])?"#"+e(b[0]).toUpperCase()+e(b[1]).toUpperCase()+e(b[2]).toUpperCase():null:null}function h(a){return d(a)?(3===a.length&&(a=a.charAt(0)+a.charAt(0)+a.charAt(1)+a.charAt(1)+a.charAt(2)+a.charAt(2)),"rgb("+f(a.substr(0,2))+","+f(a.substr(2,2))+","+f(a.substr(4,2))+")"):void 0}function i(a){return a.replace(/\s/g,"")}return function(a){if(!a)return null;var c=null,d=/^rgba?\((.*)\);?$/,e=/^#/;return a=b(a.toString()),"transparent"===a||"rgba(0,0,0,0)"===i(a)?"transparent":d.test(a)?g(a.match(d)[1]):e.test(a)?h(a.split("#").reverse()[0]):(c=a.split(","),1===c.length?h(a):3===c.length||4===c.length?g(a):void 0)}}(),jQuery&&jQuery.extend({rgbHex:function(a){return window.rgbHex(a)}});
+/*! wColorPicker - v2.1.7 - 2013-09-27 */!function(a){function b(b,c){this.$el=a(b),this.options=c,this.init=!1,this.generate()}b.prototype={generate:function(){return this.$colorPicker||(this.$noneColorPalette=this._createPalette("none",[["transparent"]]),this.$simpleColorPalette=this._createPalette("simple",a.fn.wColorPicker.simpleColors),this.$mixedColorPalette=this._createPalette("mixed",a.fn.wColorPicker.mixedColors),this.$colorTarget=a('<div class="wColorPicker-color-target"></div>'),this.$customInput=a('<input type="text" class="wColorPicker-custom-input"/>').keyup(a.proxy(this._customInputKeyup,this)),this.options.dropperButton&&(this.$dropperButton=this._createDropperButton()),this.$colorPickerPalettesHolder=a('<div class="wColorPicker-palettes-holder"></div>').append(this.$noneColorPalette).append(this.$colorTarget).append(this.$customInput).append(this.$dropperButton).append("<br/>").append(this.$simpleColorPalette).append(this.$mixedColorPalette),this.$colorPickerHolder=a('<div class="wColorPicker-holder"></div>').append(this.$colorPickerPalettesHolder),this.$colorPickerBg=a('<div class="wColorPicker-bg"></div>'),this.$colorPicker=a('<div class="wColorPicker" title=""></div>').mouseenter(function(a){a.stopPropagation()}).bind("mouseenter mousemove click",function(a){a.stopPropagation()}).append(this.$colorPickerBg).append(this.$colorPickerHolder),this.setOpacity(this.options.opacity),this.setTheme(this.options.theme),this.setColor(this.options.color),a("body").append(this.$colorPicker),this.width=this.$colorPickerPalettesHolder.width(),this.height=this.$colorPickerPalettesHolder.height(),this.$colorPickerPalettesHolder.width(this.width),this.$colorPickerPalettesHolder.height(this.height),this.$el.append(this.$colorPicker),this.setMode(this.options.mode),this.setPosition(this.options.position)),this.init=!0,this},setTheme:function(a){this.$colorPicker.attr("class",this.$colorPicker.attr("class").replace(/wColorPicker-theme-.+\s|wColorPicker-theme-.+$/,"")),this.$colorPicker.addClass("wColorPicker-theme-"+a)},setOpacity:function(a){this.$colorPickerBg.css("opacity",a)},setColor:function(a){return window.rgbHex(a)?(this.options.color=a,this.$colorTarget.css("backgroundColor",a),this.$customInput.val(a),this.init&&this.options.onSelect&&this.options.onSelect.apply(this,[a]),void 0):!0},setMode:function(b){var c=this,d=function(){c._toggleEffect("show")},e=function(){c._toggleEffect("hide")};if("flat"===b?this.$colorPicker.removeClass("wColorPicker-zindex").css({position:"relative",display:""}):this.$colorPicker.addClass("wColorPicker-zindex").css({position:"absolute"}).hide(),this.$el.find("wColorPicker-button").remove(),this.$el.unbind("mouseenter",d).unbind("mouseleave",e),a(document).unbind("click",e),"flat"!==b){var f=null,g=null,h=function(a){a.stopPropagation(),c.options.generateButton&&g.css("backgroundColor",c.options.color),c._toggleEffect()};this.options.generateButton&&(f=a('<div class="wColorPicker-button"></div>'),g=a('<div class="wColorPicker-button-color"></div>').css("backgroundColor",this.options.color),this.$el.append(f),f.append(g.height(this.$el.height()-f.outerHeight(!0)))),this.$noneColorPalette.bind("click",h),this.$simpleColorPalette.bind("click",h),this.$mixedColorPalette.bind("click",h)}"click"===b?(this.$el.click(function(a){c._toggleEffect(),a.stopPropagation()}),this.$colorPicker.click(function(a){a.stopPropagation()}),a(document).bind("click",e)):"hover"===b&&this.$el.bind("mouseenter",d).bind("mouseleave",e)},setEffect:function(a){return"flat"===this.options.mode?!0:(this.$colorPicker.css("opacity",1),this.$colorPickerHolder.width(this.width).height(this.height),"fade"===a?this.$colorPicker.css("opacity",0):"slide"===a&&this.$colorPickerHolder.width("x"===this.positionAxis?0:this.width).height("y"===this.positionAxis?0:this.height),void 0)},setPosition:function(a){if("flat"===this.options.mode)return!0;var b=this.$el.outerWidth(),c=this.$el.outerHeight(),d=this.$el.outerWidth()/2-this.$colorPicker.outerWidth()/2,e=this.$el.outerHeight()/2-this.$colorPicker.outerHeight()/2,f={left:"",right:"",top:"",bottom:""},g=this.options.position.charAt(0);switch("t"===g||"b"===g?this.positionAxis="y":("l"===g||"r"===g)&&(this.positionAxis="x"),a){case"tl":f.left=0,f.bottom=c;break;case"tc":f.left=d,f.bottom=c;break;case"tr":f.right=0,f.bottom=c;break;case"rt":f.left=b,f.top=0;break;case"rm":f.left=b,f.top=e;break;case"rb":f.left=b,f.bottom=0;break;case"br":f.right=0,f.top=c;break;case"bc":f.left=d,f.top=c;break;case"bl":f.left=0,f.top=c;break;case"lb":f.right=b,f.bottom=0;break;case"lm":f.right=b,f.top=e;break;case"lt":f.right=b,f.top=0}this.$colorPicker.css(f),this.setEffect(this.options.effect)},_createPalette:function(b,c){var d=0,e=0,f=0,g=0,h=null,i=a('<div class="wColorPicker-palette wColorPicker-palette-'+b+'"></div>');for(d=0,e=c.length;e>d;d++){for(f=0,g=c[d].length;g>f;f++)h=this._createColor(f,c[d][f]),0===d&&h.addClass("wColorPicker-palette-color-top"),0===f&&h.addClass("wColorPicker-palette-color-left"),i.append(h);e>d&&i.append("<br/>")}return i},_createColor:function(b,c){var d=this;return a('<div class="wColorPicker-palette-color"></div>').attr("id","wColorPicker-palette-color-"+b).addClass("wColorPicker-palette-color-"+b).css("backgroundColor",c).hover(function(){d._colorMouseenter(a(this))},function(){d._colorMouseleave(a(this))}).click(function(){d.setColor(window.rgbHex(a(this).css("backgroundColor")))})},_createDropperButton:function(){return a('<div class="wColorPicker-dropper"></div>').click(a.proxy(this.options.onDropper,this))},_customInputKeyup:function(b){var c=a(b.target).val();window.rgbHex(c)&&(this.$colorTarget.css("backgroundColor",c),13===b.keyCode&&this.setColor(c))},_colorMouseenter:function(a){var b=window.rgbHex(a.css("backgroundColor"));a.addClass("active").prev().addClass("active-right"),a.prevAll("."+a.attr("id")+":first").addClass("active-bottom"),this.$colorTarget.css("backgroundColor",b),this.$customInput.val(b),this.options.onMouseover&&this.options.onMouseover.apply(this,[b])},_colorMouseleave:function(a){a.removeClass("active").prev().removeClass("active-right"),a.prevAll("."+a.attr("id")+":first").removeClass("active-bottom"),this.$colorTarget.css("backgroundColor",this.options.color),this.$customInput.val(this.options.color),this.options.onMouseout&&this.options.onMouseout.apply(this,[this.options.color])},_toggleEffect:function(a){var b=this.$colorPicker.hasClass("wColorPicker-visible");(!a||"show"===a&&b===!1||"hide"===a&&b===!0)&&(b||this.setPosition(this.options.position),this["_"+this.options.effect+"Effect"+(b?"Hide":"Show")](),this.$colorPicker.toggleClass("wColorPicker-visible"))},_noneEffectShow:function(){this.$colorPicker.css("display","inline-block")},_noneEffectHide:function(){this.$colorPicker.hide()},_fadeEffectShow:function(){this.$colorPicker.stop(!0,!1).css({display:"inline-block"}).animate({opacity:1},this.options.showSpeed)},_fadeEffectHide:function(){this.$colorPicker.stop(!0,!1).animate({opacity:0},this.options.hideSpeed,a.proxy(function(){this.$colorPicker.hide()},this))},_slideEffectShow:function(){var a="y"===this.positionAxis?{height:this.height}:{width:this.width};this.$colorPicker.css("display","inline-block"),this.$colorPickerHolder.stop(!0,!1).animate(a,this.options.showSpeed)},_slideEffectHide:function(){var b="y"===this.positionAxis?{height:0}:{width:0};this.$colorPickerHolder.stop(!0,!1).animate(b,this.options.hideSpeed,a.proxy(function(){this.$colorPicker.hide()},this))}},a.fn.wColorPicker=function(c,d){function e(d){var e,f=a.data(d,"wColorPicker");return f||(e=a.extend({},a.fn.wColorPicker.defaults,c),e.color=window.rgbHex(e.color)?e.color:"transparent",f=new b(d,e),a.data(d,"wColorPicker",f)),f}if("string"==typeof c){var f=[],g=null,h=null,i=null;return h=this.each(function(){g=a(this).data("wColorPicker"),g&&(i=(d?"set":"get")+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase(),g[c]?f.push(g[c].apply(g,[d])):d?(g[i]&&g[i].apply(g,[d]),g.options[c]&&(g.options[c]=d)):g[i]?f.push(g[i].apply(g,[d])):g.options[c]?f.push(g.options[c]):f.push(null))}),1===f.length?f[0]:f.length>0?f:h}return this.each(function(){e(this)})},a.fn.wColorPicker.defaults={theme:"classic",opacity:.9,color:"#FF0000",mode:"flat",position:"bl",generateButton:!0,dropperButton:!1,effect:"slide",showSpeed:500,hideSpeed:500,onMouseover:null,onMouseout:null,onSelect:null,onDropper:null},a.fn.wColorPicker.mixedColors=[["#000000","#003300","#006600","#009900","#00CC00","#00FF00","#330000","#333300","#336600","#339900","#33CC00","#33FF00","#660000","#663300","#666600","#669900","#66CC00","#66FF00"],["#000033","#003333","#006633","#009933","#00CC33","#00FF33","#330033","#333333","#336633","#339933","#33CC33","#33FF33","#660033","#663333","#666633","#669933","#66CC33","#66FF33"],["#000066","#003366","#006666","#009966","#00CC66","#00FF66","#330066","#333366","#336666","#339966","#33CC66","#33FF66","#660066","#663366","#666666","#669966","#66CC66","#66FF66"],["#000099","#003399","#006699","#009999","#00CC99","#00FF99","#330099","#333399","#336699","#339999","#33CC99","#33FF99","#660099","#663399","#666699","#669999","#66CC99","#66FF99"],["#0000CC","#0033CC","#0066CC","#0099CC","#00CCCC","#00FFCC","#3300CC","#3333CC","#3366CC","#3399CC","#33CCCC","#33FFCC","#6600CC","#6633CC","#6666CC","#6699CC","#66CCCC","#66FFCC"],["#0000FF","#0033FF","#0066FF","#0099FF","#00CCFF","#00FFFF","#3300FF","#3333FF","#3366FF","#3399FF","#33CCFF","#33FFFF","#6600FF","#6633FF","#6666FF","#6699FF","#66CCFF","#66FFFF"],["#990000","#993300","#996600","#999900","#99CC00","#99FF00","#CC0000","#CC3300","#CC6600","#CC9900","#CCCC00","#CCFF00","#FF0000","#FF3300","#FF6600","#FF9900","#FFCC00","#FFFF00"],["#990033","#993333","#996633","#999933","#99CC33","#99FF33","#CC0033","#CC3333","#CC6633","#CC9933","#CCCC33","#CCFF33","#FF0033","#FF3333","#FF6633","#FF9933","#FFCC33","#FFFF33"],["#990066","#993366","#996666","#999966","#99CC66","#99FF66","#CC0066","#CC3366","#CC6666","#CC9966","#CCCC66","#CCFF66","#FF0066","#FF3366","#FF6666","#FF9966","#FFCC66","#FFFF66"],["#990099","#993399","#996699","#999999","#99CC99","#99FF99","#CC0099","#CC3399","#CC6699","#CC9999","#CCCC99","#CCFF99","#FF0099","#FF3399","#FF6699","#FF9999","#FFCC99","#FFFF99"],["#9900CC","#9933CC","#9966CC","#9999CC","#99CCCC","#99FFCC","#CC00CC","#CC33CC","#CC66CC","#CC99CC","#CCCCCC","#CCFFCC","#FF00CC","#FF33CC","#FF66CC","#FF99CC","#FFCCCC","#FFFFCC"],["#9900FF","#9933FF","#9966FF","#9999FF","#99CCFF","#99FFFF","#CC00FF","#CC33FF","#CC66FF","#CC99FF","#CCCCFF","#CCFFFF","#FF00FF","#FF33FF","#FF66FF","#FF99FF","#FFCCFF","#FFFFFF"]],a.fn.wColorPicker.simpleColors=[["#000000"],["#333333"],["#666666"],["#999999"],["#CCCCCC"],["#FFFFFF"],["#FF0000"],["#00FF00"],["#0000FF"],["#FFFF00"],["#00FFFF"],["#FF00FF"]]}(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/package.json b/static/js/wpaint/package.json
new file mode 100644
index 0000000..49ea26f
--- /dev/null
+++ b/static/js/wpaint/package.json
@@ -0,0 +1,25 @@
+{
+ "name": "wPaint",
+ "title": "wPaint jQuery Paint Plugin",
+ "version": "2.5.0",
+ "description": "A jQuery paint plugin for a simple drawing surface that you can easily pop into your pages, similar to the basic windows paint program.",
+ "main": "wPaint.js",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/websanova/wPaint"
+ },
+ "author": {
+ "name": "Websanova",
+ "email": "rob@websanova.com",
+ "url": "http://websanova.com"
+ },
+ "homepage" : "http://wpaint.websanova.com",
+ "license": "MIT, GPL",
+ "dependencies": {
+ "grunt-contrib-uglify": "",
+ "grunt-contrib-jshint": "",
+ "grunt-contrib-stylus": "",
+ "grunt-contrib-concat": "",
+ "grunt-contrib-watch": ""
+ }
+} \ No newline at end of file
diff --git a/static/js/wpaint/plugins/file/img/icons-menu-main-file.png b/static/js/wpaint/plugins/file/img/icons-menu-main-file.png
new file mode 100644
index 0000000..cda4bde
--- /dev/null
+++ b/static/js/wpaint/plugins/file/img/icons-menu-main-file.png
Binary files differ
diff --git a/static/js/wpaint/plugins/file/src/wPaint.menu.main.file.js b/static/js/wpaint/plugins/file/src/wPaint.menu.main.file.js
new file mode 100644
index 0000000..15cfa46
--- /dev/null
+++ b/static/js/wpaint/plugins/file/src/wPaint.menu.main.file.js
@@ -0,0 +1,75 @@
+(function ($) {
+ var img = 'plugins/file/img/icons-menu-main-file.png';
+
+ // extend menu
+ $.extend(true, $.fn.wPaint.menus.main.items, {
+ save: {
+ icon: 'generic',
+ title: 'Save Image',
+ img: img,
+ index: 0,
+ callback: function () {
+ this.options.saveImg.apply(this, [this.getImage()]);
+ }
+ },
+ loadBg: {
+ icon: 'generic',
+ group: 'loadImg',
+ title: 'Load Image to Foreground',
+ img: img,
+ index: 2,
+ callback: function () {
+ this.options.loadImgFg.apply(this, []);
+ }
+ },
+ loadFg: {
+ icon: 'generic',
+ group: 'loadImg',
+ title: 'Load Image to Background',
+ img: img,
+ index: 1,
+ callback: function () {
+ this.options.loadImgBg.apply(this, []);
+ }
+ }
+ });
+
+ // extend defaults
+ $.extend($.fn.wPaint.defaults, {
+ saveImg: null, // callback triggerd on image save
+ loadImgFg: null, // callback triggered on image fg
+ loadImgBg: null // callback triggerd on image bg
+ });
+
+ // extend functions
+ $.fn.wPaint.extend({
+ _showFileModal: function (type, images) {
+ var _this = this,
+ $content = $('<div></div>'),
+ $img = null;
+
+ function appendContent(type, image) {
+ function imgClick(e) {
+
+ // just in case to not draw on canvas
+ e.stopPropagation();
+ if (type === 'fg') { _this.setImage(image); }
+ else if (type === 'bg') { _this.setBg(image, null, null, true); }
+ }
+
+ $img.on('click', imgClick);
+ }
+
+ for (var i = 0, ii = images.length; i < ii; i++) {
+ $img = $('<img class="wPaint-modal-img"/>').attr('src', images[i]);
+ $img = $('<div class="wPaint-modal-img-holder"></div>').append($img);
+
+ (appendContent)(type, images[i]);
+
+ $content.append($img);
+ }
+
+ this._showModal($content);
+ }
+ });
+})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/plugins/file/wPaint.menu.main.file.min.js b/static/js/wpaint/plugins/file/wPaint.menu.main.file.min.js
new file mode 100644
index 0000000..a2631b7
--- /dev/null
+++ b/static/js/wpaint/plugins/file/wPaint.menu.main.file.min.js
@@ -0,0 +1 @@
+/*! wPaint - v2.5.0 - 2014-03-01 */!function(a){var b="plugins/file/img/icons-menu-main-file.png";a.extend(!0,a.fn.wPaint.menus.main.items,{save:{icon:"generic",title:"Save Image",img:b,index:0,callback:function(){this.options.saveImg.apply(this,[this.getImage()])}},loadBg:{icon:"generic",group:"loadImg",title:"Load Image to Foreground",img:b,index:2,callback:function(){this.options.loadImgFg.apply(this,[])}},loadFg:{icon:"generic",group:"loadImg",title:"Load Image to Background",img:b,index:1,callback:function(){this.options.loadImgBg.apply(this,[])}}}),a.extend(a.fn.wPaint.defaults,{saveImg:null,loadImgFg:null,loadImgBg:null}),a.fn.wPaint.extend({_showFileModal:function(b,c){function d(a,b){function c(c){c.stopPropagation(),"fg"===a?e.setImage(b):"bg"===a&&e.setBg(b,null,null,!0)}g.on("click",c)}for(var e=this,f=a("<div></div>"),g=null,h=0,i=c.length;i>h;h++)g=a('<img class="wPaint-modal-img"/>').attr("src",c[h]),g=a('<div class="wPaint-modal-img-holder"></div>').append(g),d(b,c[h]),f.append(g);this._showModal(f)}})}(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/plugins/main/img/cursor-bucket.png b/static/js/wpaint/plugins/main/img/cursor-bucket.png
new file mode 100644
index 0000000..b6757ad
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-bucket.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-crosshair.png b/static/js/wpaint/plugins/main/img/cursor-crosshair.png
new file mode 100644
index 0000000..362e069
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-crosshair.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-dropper.png b/static/js/wpaint/plugins/main/img/cursor-dropper.png
new file mode 100644
index 0000000..e8396d1
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-dropper.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser1.png b/static/js/wpaint/plugins/main/img/cursor-eraser1.png
new file mode 100644
index 0000000..1a25ec5
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser1.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser10.png b/static/js/wpaint/plugins/main/img/cursor-eraser10.png
new file mode 100644
index 0000000..5f5d83f
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser10.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser2.png b/static/js/wpaint/plugins/main/img/cursor-eraser2.png
new file mode 100644
index 0000000..d15f875
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser2.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser3.png b/static/js/wpaint/plugins/main/img/cursor-eraser3.png
new file mode 100644
index 0000000..c81814d
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser3.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser4.png b/static/js/wpaint/plugins/main/img/cursor-eraser4.png
new file mode 100644
index 0000000..c512bfc
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser4.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser5.png b/static/js/wpaint/plugins/main/img/cursor-eraser5.png
new file mode 100644
index 0000000..fff0873
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser5.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser6.png b/static/js/wpaint/plugins/main/img/cursor-eraser6.png
new file mode 100644
index 0000000..d413f05
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser6.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser7.png b/static/js/wpaint/plugins/main/img/cursor-eraser7.png
new file mode 100644
index 0000000..52876a5
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser7.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser8.png b/static/js/wpaint/plugins/main/img/cursor-eraser8.png
new file mode 100644
index 0000000..6c1577b
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser8.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-eraser9.png b/static/js/wpaint/plugins/main/img/cursor-eraser9.png
new file mode 100644
index 0000000..4441a3e
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-eraser9.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/cursor-pencil.png b/static/js/wpaint/plugins/main/img/cursor-pencil.png
new file mode 100644
index 0000000..d54322d
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/cursor-pencil.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/icon-group-arrow.png b/static/js/wpaint/plugins/main/img/icon-group-arrow.png
new file mode 100644
index 0000000..ff501ac
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/icon-group-arrow.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/img/icons-menu-main.png b/static/js/wpaint/plugins/main/img/icons-menu-main.png
new file mode 100644
index 0000000..4b1a90b
--- /dev/null
+++ b/static/js/wpaint/plugins/main/img/icons-menu-main.png
Binary files differ
diff --git a/static/js/wpaint/plugins/main/src/fillArea.min.js b/static/js/wpaint/plugins/main/src/fillArea.min.js
new file mode 100644
index 0000000..08aa950
--- /dev/null
+++ b/static/js/wpaint/plugins/main/src/fillArea.min.js
@@ -0,0 +1 @@
+!function(){window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.fillArea=function(a,b,c){function d(a){return{r:p[a],g:p[a+1],b:p[a+2],a:p[a+3]}}function e(a){p[a]=c.r,p[a+1]=c.g,p[a+2]=c.b,p[a+3]=c.a}function f(a){return g.r===a.r&&g.g===a.g&&g.b===a.b&&g.a===a.a}if(!a||!b||!c)return!0;var g,h,i,j,k,l,m=this.canvas.width,n=this.canvas.height,o=this.getImageData(0,0,m,n),p=o.data,q=[[a,b]];if(g=d(4*(b*m+a)),l=this.canvas.style.color,this.canvas.style.color=c,c=this.canvas.style.color.match(/^rgba?\((.*)\);?$/)[1].split(","),this.canvas.style.color=l,c={r:parseInt(c[0],10),g:parseInt(c[1],10),b:parseInt(c[2],10),a:parseInt(c[3]||255,10)},f(c))return!0;for(;q.length;){for(h=q.pop(),i=4*(h[1]*m+h[0]);h[1]-->=0&&f(d(i));)i-=4*m;for(i+=4*m,++h[1],j=!1,k=!1;h[1]++<n-1&&f(d(i));)e(i),h[0]>0&&(f(d(i-4))?j||(q.push([h[0]-1,h[1]]),j=!0):j&&(j=!1)),h[0]<m-1&&(f(d(i+4))?k||(q.push([h[0]+1,h[1]]),k=!0):k&&(k=!1)),i+=4*m}this.putImageData(o,0,0)})}(); \ No newline at end of file
diff --git a/static/js/wpaint/plugins/main/src/wPaint.menu.main.js b/static/js/wpaint/plugins/main/src/wPaint.menu.main.js
new file mode 100644
index 0000000..459bb73
--- /dev/null
+++ b/static/js/wpaint/plugins/main/src/wPaint.menu.main.js
@@ -0,0 +1,338 @@
+(function ($) {
+
+ // setup menu
+ $.fn.wPaint.menus.main = {
+ img: 'plugins/main/img/icons-menu-main.png',
+ items: {
+ undo: {
+ icon: 'generic',
+ title: 'Undo',
+ index: 0,
+ callback: function () { this.undo(); }
+ },
+ redo: {
+ icon: 'generic',
+ title: 'Redo',
+ index: 1,
+ callback: function () { this.redo(); }
+ },
+ clear: {
+ icon: 'generic',
+ title: 'Clear',
+ index: 2,
+ callback: function () { this.clear(); }
+ },
+ rectangle: {
+ icon: 'activate',
+ title: 'Rectangle',
+ index: 3,
+ callback: function () { this.setMode('rectangle'); }
+ },
+ ellipse: {
+ icon: 'activate',
+ title: 'Ellipse',
+ index: 4,
+ callback: function () { this.setMode('ellipse'); }
+ },
+ line: {
+ icon: 'activate',
+ title: 'Line',
+ index: 5,
+ callback: function () { this.setMode('line'); }
+ },
+ pencil: {
+ icon: 'activate',
+ title: 'Pencil',
+ index: 6,
+ callback: function () { this.setMode('pencil'); }
+ },
+ eraser: {
+ icon: 'activate',
+ title: 'Eraser',
+ index: 8,
+ callback: function () { this.setMode('eraser'); }
+ },
+ bucket: {
+ icon: 'activate',
+ title: 'Bucket',
+ index: 9,
+ callback: function () { this.setMode('bucket'); }
+ },
+ fillStyle: {
+ title: 'Fill Color',
+ icon: 'colorPicker',
+ callback: function (color) { this.setFillStyle(color); }
+ },
+ lineWidth: {
+ icon: 'select',
+ title: 'Stroke Width',
+ range: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+ value: 2,
+ callback: function (width) { this.setLineWidth(width); }
+ },
+ strokeStyle: {
+ icon: 'colorPicker',
+ title: 'Stroke Color',
+ callback: function (color) { this.setStrokeStyle(color); }
+ }
+ }
+ };
+
+ // extend cursors
+ $.extend($.fn.wPaint.cursors, {
+ 'default': {path: 'plugins/main/img/cursor-crosshair.png', left: 7, top: 7},
+ dropper: {path: 'plugins/main/img/cursor-dropper.png', left: 0, top: 12},
+ pencil: {path: 'plugins/main/img/cursor-pencil.png', left: 0, top: 11.99},
+ bucket: {path: 'plugins/main/img/cursor-bucket.png', left: 0, top: 10},
+ eraser1: {path: 'plugins/main/img/cursor-eraser1.png', left: 1, top: 1},
+ eraser2: {path: 'plugins/main/img/cursor-eraser2.png', left: 2, top: 2},
+ eraser3: {path: 'plugins/main/img/cursor-eraser3.png', left: 2, top: 2},
+ eraser4: {path: 'plugins/main/img/cursor-eraser4.png', left: 3, top: 3},
+ eraser5: {path: 'plugins/main/img/cursor-eraser5.png', left: 3, top: 3},
+ eraser6: {path: 'plugins/main/img/cursor-eraser6.png', left: 4, top: 4},
+ eraser7: {path: 'plugins/main/img/cursor-eraser7.png', left: 4, top: 4},
+ eraser8: {path: 'plugins/main/img/cursor-eraser8.png', left: 5, top: 5 },
+ eraser9: {path: 'plugins/main/img/cursor-eraser9.png', left: 5, top: 5},
+ eraser10: {path: 'plugins/main/img/cursor-eraser10.png', left: 6, top: 6}
+ });
+
+ // extend defaults
+ $.extend($.fn.wPaint.defaults, {
+ mode: 'pencil', // set mode
+ lineWidth: '3', // starting line width
+ fillStyle: '#FFFFFF', // starting fill style
+ strokeStyle: '#FFFF00' // start stroke style
+ });
+
+ // extend functions
+ $.fn.wPaint.extend({
+ undoCurrent: -1,
+ undoArray: [],
+ setUndoFlag: true,
+
+ generate: function () {
+ this.menus.all.main = this._createMenu('main', {
+ offsetLeft: this.options.menuOffsetLeft,
+ offsetTop: this.options.menuOffsetTop
+ });
+ },
+
+ _init: function () {
+ // must add undo on init to set the first undo as the initial drawing (bg or blank)
+ this._addUndo();
+ this.menus.all.main._setIconDisabled('clear', true);
+ },
+
+ setStrokeStyle: function (color) {
+ this.options.strokeStyle = color;
+ this.menus.all.main._setColorPickerValue('strokeStyle', color);
+ },
+
+ setLineWidth: function (width) {
+ this.options.lineWidth = width;
+ this.menus.all.main._setSelectValue('lineWidth', width);
+
+ // reset cursor here based on mode in case we need to update cursor (for instance when changing cursor for eraser sizes)
+ this.setCursor(this.options.mode);
+ },
+
+ setFillStyle: function (color) {
+ this.options.fillStyle = color;
+ this.menus.all.main._setColorPickerValue('fillStyle', color);
+ },
+
+ setCursor: function (cursor) {
+ if (cursor === 'eraser') {
+ this.setCursor('eraser' + this.options.lineWidth);
+ }
+ },
+
+ /****************************************
+ * undo / redo
+ ****************************************/
+ undo: function () {
+ if (this.undoArray[this.undoCurrent - 1]) {
+ this._setUndo(--this.undoCurrent);
+ }
+
+ this._undoToggleIcons();
+ },
+
+ redo: function () {
+ if (this.undoArray[this.undoCurrent + 1]) {
+ this._setUndo(++this.undoCurrent);
+ }
+
+ this._undoToggleIcons();
+ },
+
+ _addUndo: function () {
+
+ //if it's not at the end of the array we need to repalce the current array position
+ if (this.undoCurrent < this.undoArray.length - 1) {
+ this.undoArray[++this.undoCurrent] = this.getImage(false);
+ }
+ else { // owtherwise we push normally here
+ this.undoArray.push(this.getImage(false));
+
+ //if we're at the end of the array we need to slice off the front - in increment required
+ if (this.undoArray.length > this.undoMax) {
+ this.undoArray = this.undoArray.slice(1, this.undoArray.length);
+ }
+ //if we're NOT at the end of the array, we just increment
+ else { this.undoCurrent++; }
+ }
+
+ //for undo's then a new draw we want to remove everything afterwards - in most cases nothing will happen here
+ while (this.undoCurrent !== this.undoArray.length - 1) { this.undoArray.pop(); }
+
+ this._undoToggleIcons();
+ this.menus.all.main._setIconDisabled('clear', false);
+ },
+
+ _undoToggleIcons: function () {
+ var undoIndex = (this.undoCurrent > 0 && this.undoArray.length > 1) ? 0 : 1,
+ redoIndex = (this.undoCurrent < this.undoArray.length - 1) ? 2 : 3;
+
+ this.menus.all.main._setIconDisabled('undo', undoIndex === 1 ? true : false);
+ this.menus.all.main._setIconDisabled('redo', redoIndex === 3 ? true : false);
+ },
+
+ _setUndo: function (undoCurrent) {
+ this.setImage(this.undoArray[undoCurrent], null, null, true);
+ },
+
+ /****************************************
+ * clear
+ ****************************************/
+ clear: function () {
+
+ // only run if not disabled (make sure we only run one clear at a time)
+ if (!this.menus.all.main._isIconDisabled('clear')) {
+ this.ctx.clearRect(0, 0, this.width, this.height);
+ this._addUndo();
+ this.menus.all.main._setIconDisabled('clear', true);
+ }
+ },
+
+ /****************************************
+ * rectangle
+ ****************************************/
+ _drawRectangleDown: function (e) { this._drawShapeDown(e); },
+
+ _drawRectangleMove: function (e) {
+ this._drawShapeMove(e);
+
+ this.ctxTemp.rect(e.x, e.y, e.w, e.h);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawRectangleUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * ellipse
+ ****************************************/
+ _drawEllipseDown: function (e) { this._drawShapeDown(e); },
+
+ _drawEllipseMove: function (e) {
+ this._drawShapeMove(e);
+
+ this.ctxTemp.ellipse(e.x, e.y, e.w, e.h);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawEllipseUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * line
+ ****************************************/
+ _drawLineDown: function (e) { this._drawShapeDown(e); },
+
+ _drawLineMove: function (e) {
+ this._drawShapeMove(e, 1);
+
+ var xo = this.canvasTempLeftOriginal;
+ var yo = this.canvasTempTopOriginal;
+
+ if (e.pageX < xo) { e.x = e.x + e.w; e.w = e.w * - 1; }
+ if (e.pageY < yo) { e.y = e.y + e.h; e.h = e.h * - 1; }
+
+ this.ctxTemp.lineJoin = 'round';
+ this.ctxTemp.beginPath();
+ this.ctxTemp.moveTo(e.x, e.y);
+ this.ctxTemp.lineTo(e.x + e.w, e.y + e.h);
+ this.ctxTemp.closePath();
+ this.ctxTemp.stroke();
+ },
+
+ _drawLineUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * pencil
+ ****************************************/
+ _drawPencilDown: function (e) {
+ this.ctx.lineJoin = 'round';
+ this.ctx.lineCap = 'round';
+ this.ctx.strokeStyle = this.options.strokeStyle;
+ this.ctx.fillStyle = this.options.strokeStyle;
+ this.ctx.lineWidth = this.options.lineWidth;
+
+ //draw single dot in case of a click without a move
+ this.ctx.beginPath();
+ this.ctx.arc(e.pageX, e.pageY, this.options.lineWidth / 2, 0, Math.PI * 2, true);
+ this.ctx.closePath();
+ this.ctx.fill();
+
+ //start the path for a drag
+ this.ctx.beginPath();
+ this.ctx.moveTo(e.pageX, e.pageY);
+ },
+
+ _drawPencilMove: function (e) {
+ this.ctx.lineTo(e.pageX, e.pageY);
+ this.ctx.stroke();
+ },
+
+ _drawPencilUp: function () {
+ this.ctx.closePath();
+ this._addUndo();
+ },
+
+ /****************************************
+ * eraser
+ ****************************************/
+ _drawEraserDown: function (e) {
+ this.ctx.save();
+ this.ctx.globalCompositeOperation = 'destination-out';
+ this._drawPencilDown(e);
+ },
+
+ _drawEraserMove: function (e) {
+ this._drawPencilMove(e);
+ },
+
+ _drawEraserUp: function (e) {
+ this._drawPencilUp(e);
+ this.ctx.restore();
+ },
+
+ /****************************************
+ * bucket
+ ****************************************/
+ _drawBucketDown: function (e) {
+ this.ctx.fillArea(e.pageX, e.pageY, this.options.fillStyle);
+ this._addUndo();
+ }
+ });
+})(jQuery);
diff --git a/static/js/wpaint/plugins/main/wPaint.menu.main.min.js b/static/js/wpaint/plugins/main/wPaint.menu.main.min.js
new file mode 100644
index 0000000..0a950c5
--- /dev/null
+++ b/static/js/wpaint/plugins/main/wPaint.menu.main.min.js
@@ -0,0 +1 @@
+/*! wPaint - v2.5.0 - 2014-03-01 */!function(a){a.fn.wPaint.menus.main={img:"plugins/main/img/icons-menu-main.png",items:{undo:{icon:"generic",title:"Undo",index:0,callback:function(){this.undo()}},redo:{icon:"generic",title:"Redo",index:1,callback:function(){this.redo()}},clear:{icon:"generic",title:"Clear",index:2,callback:function(){this.clear()}},rectangle:{icon:"activate",title:"Rectangle",index:3,callback:function(){this.setMode("rectangle")}},ellipse:{icon:"activate",title:"Ellipse",index:4,callback:function(){this.setMode("ellipse")}},line:{icon:"activate",title:"Line",index:5,callback:function(){this.setMode("line")}},pencil:{icon:"activate",title:"Pencil",index:6,callback:function(){this.setMode("pencil")}},eraser:{icon:"activate",title:"Eraser",index:8,callback:function(){this.setMode("eraser")}},bucket:{icon:"activate",title:"Bucket",index:9,callback:function(){this.setMode("bucket")}},fillStyle:{title:"Fill Color",icon:"colorPicker",callback:function(a){this.setFillStyle(a)}},lineWidth:{icon:"select",title:"Stroke Width",range:[1,2,3,4,5,6,7,8,9,10],value:2,callback:function(a){this.setLineWidth(a)}},strokeStyle:{icon:"colorPicker",title:"Stroke Color",callback:function(a){this.setStrokeStyle(a)}}}},a.extend(a.fn.wPaint.cursors,{"default":{path:"plugins/main/img/cursor-crosshair.png",left:7,top:7},dropper:{path:"plugins/main/img/cursor-dropper.png",left:0,top:12},pencil:{path:"plugins/main/img/cursor-pencil.png",left:0,top:11.99},bucket:{path:"plugins/main/img/cursor-bucket.png",left:0,top:10},eraser1:{path:"plugins/main/img/cursor-eraser1.png",left:1,top:1},eraser2:{path:"plugins/main/img/cursor-eraser2.png",left:2,top:2},eraser3:{path:"plugins/main/img/cursor-eraser3.png",left:2,top:2},eraser4:{path:"plugins/main/img/cursor-eraser4.png",left:3,top:3},eraser5:{path:"plugins/main/img/cursor-eraser5.png",left:3,top:3},eraser6:{path:"plugins/main/img/cursor-eraser6.png",left:4,top:4},eraser7:{path:"plugins/main/img/cursor-eraser7.png",left:4,top:4},eraser8:{path:"plugins/main/img/cursor-eraser8.png",left:5,top:5},eraser9:{path:"plugins/main/img/cursor-eraser9.png",left:5,top:5},eraser10:{path:"plugins/main/img/cursor-eraser10.png",left:6,top:6}}),a.extend(a.fn.wPaint.defaults,{mode:"pencil",lineWidth:"3",fillStyle:"#FFFFFF",strokeStyle:"#FFFF00"}),a.fn.wPaint.extend({undoCurrent:-1,undoArray:[],setUndoFlag:!0,generate:function(){this.menus.all.main=this._createMenu("main",{offsetLeft:this.options.menuOffsetLeft,offsetTop:this.options.menuOffsetTop})},_init:function(){this._addUndo(),this.menus.all.main._setIconDisabled("clear",!0)},setStrokeStyle:function(a){this.options.strokeStyle=a,this.menus.all.main._setColorPickerValue("strokeStyle",a)},setLineWidth:function(a){this.options.lineWidth=a,this.menus.all.main._setSelectValue("lineWidth",a),this.setCursor(this.options.mode)},setFillStyle:function(a){this.options.fillStyle=a,this.menus.all.main._setColorPickerValue("fillStyle",a)},setCursor:function(a){"eraser"===a&&this.setCursor("eraser"+this.options.lineWidth)},undo:function(){this.undoArray[this.undoCurrent-1]&&this._setUndo(--this.undoCurrent),this._undoToggleIcons()},redo:function(){this.undoArray[this.undoCurrent+1]&&this._setUndo(++this.undoCurrent),this._undoToggleIcons()},_addUndo:function(){for(this.undoCurrent<this.undoArray.length-1?this.undoArray[++this.undoCurrent]=this.getImage(!1):(this.undoArray.push(this.getImage(!1)),this.undoArray.length>this.undoMax?this.undoArray=this.undoArray.slice(1,this.undoArray.length):this.undoCurrent++);this.undoCurrent!==this.undoArray.length-1;)this.undoArray.pop();this._undoToggleIcons(),this.menus.all.main._setIconDisabled("clear",!1)},_undoToggleIcons:function(){var a=this.undoCurrent>0&&this.undoArray.length>1?0:1,b=this.undoCurrent<this.undoArray.length-1?2:3;this.menus.all.main._setIconDisabled("undo",1===a?!0:!1),this.menus.all.main._setIconDisabled("redo",3===b?!0:!1)},_setUndo:function(a){this.setImage(this.undoArray[a],null,null,!0)},clear:function(){this.menus.all.main._isIconDisabled("clear")||(this.ctx.clearRect(0,0,this.width,this.height),this._addUndo(),this.menus.all.main._setIconDisabled("clear",!0))},_drawRectangleDown:function(a){this._drawShapeDown(a)},_drawRectangleMove:function(a){this._drawShapeMove(a),this.ctxTemp.rect(a.x,a.y,a.w,a.h),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawRectangleUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawEllipseDown:function(a){this._drawShapeDown(a)},_drawEllipseMove:function(a){this._drawShapeMove(a),this.ctxTemp.ellipse(a.x,a.y,a.w,a.h),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawEllipseUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawLineDown:function(a){this._drawShapeDown(a)},_drawLineMove:function(a){this._drawShapeMove(a,1);var b=this.canvasTempLeftOriginal,c=this.canvasTempTopOriginal;a.pageX<b&&(a.x=a.x+a.w,a.w=-1*a.w),a.pageY<c&&(a.y=a.y+a.h,a.h=-1*a.h),this.ctxTemp.lineJoin="round",this.ctxTemp.beginPath(),this.ctxTemp.moveTo(a.x,a.y),this.ctxTemp.lineTo(a.x+a.w,a.y+a.h),this.ctxTemp.closePath(),this.ctxTemp.stroke()},_drawLineUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawPencilDown:function(a){this.ctx.lineJoin="round",this.ctx.lineCap="round",this.ctx.strokeStyle=this.options.strokeStyle,this.ctx.fillStyle=this.options.strokeStyle,this.ctx.lineWidth=this.options.lineWidth,this.ctx.beginPath(),this.ctx.arc(a.pageX,a.pageY,this.options.lineWidth/2,0,2*Math.PI,!0),this.ctx.closePath(),this.ctx.fill(),this.ctx.beginPath(),this.ctx.moveTo(a.pageX,a.pageY)},_drawPencilMove:function(a){this.ctx.lineTo(a.pageX,a.pageY),this.ctx.stroke()},_drawPencilUp:function(){this.ctx.closePath(),this._addUndo()},_drawEraserDown:function(a){this.ctx.save(),this.ctx.globalCompositeOperation="destination-out",this._drawPencilDown(a)},_drawEraserMove:function(a){this._drawPencilMove(a)},_drawEraserUp:function(a){this._drawPencilUp(a),this.ctx.restore()},_drawBucketDown:function(a){this.ctx.fillArea(a.pageX,a.pageY,this.options.fillStyle),this._addUndo()}})}(jQuery),!function(){window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.fillArea=function(a,b,c){function d(a){return{r:p[a],g:p[a+1],b:p[a+2],a:p[a+3]}}function e(a){p[a]=c.r,p[a+1]=c.g,p[a+2]=c.b,p[a+3]=c.a}function f(a){return g.r===a.r&&g.g===a.g&&g.b===a.b&&g.a===a.a}if(!a||!b||!c)return!0;var g,h,i,j,k,l,m=this.canvas.width,n=this.canvas.height,o=this.getImageData(0,0,m,n),p=o.data,q=[[a,b]];if(g=d(4*(b*m+a)),l=this.canvas.style.color,this.canvas.style.color=c,c=this.canvas.style.color.match(/^rgba?\((.*)\);?$/)[1].split(","),this.canvas.style.color=l,c={r:parseInt(c[0],10),g:parseInt(c[1],10),b:parseInt(c[2],10),a:parseInt(c[3]||255,10)},f(c))return!0;for(;q.length;){for(h=q.pop(),i=4*(h[1]*m+h[0]);h[1]-->=0&&f(d(i));)i-=4*m;for(i+=4*m,++h[1],j=!1,k=!1;h[1]++<n-1&&f(d(i));)e(i),h[0]>0&&(f(d(i-4))?j||(q.push([h[0]-1,h[1]]),j=!0):j&&(j=!1)),h[0]<m-1&&(f(d(i+4))?k||(q.push([h[0]+1,h[1]]),k=!0):k&&(k=!1)),i+=4*m}this.putImageData(o,0,0)})}(); \ No newline at end of file
diff --git a/static/js/wpaint/plugins/shapes/img/icons-menu-main-shapes.png b/static/js/wpaint/plugins/shapes/img/icons-menu-main-shapes.png
new file mode 100644
index 0000000..b2cb874
--- /dev/null
+++ b/static/js/wpaint/plugins/shapes/img/icons-menu-main-shapes.png
Binary files differ
diff --git a/static/js/wpaint/plugins/shapes/src/shapes.min.js b/static/js/wpaint/plugins/shapes/src/shapes.min.js
new file mode 100644
index 0000000..585aa85
--- /dev/null
+++ b/static/js/wpaint/plugins/shapes/src/shapes.min.js
@@ -0,0 +1 @@
+!function(){window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.diamond=function(a,b,c,d){return a&&b&&c&&d?(this.beginPath(),this.moveTo(a+.5*c,b),this.lineTo(a,b+.5*d),this.lineTo(a+.5*c,b+d),this.lineTo(a+c,b+.5*d),this.lineTo(a+.5*c,b),this.closePath(),void 0):!0}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.ellipse=function(a,b,c,d){if(!(a&&b&&c&&d))return!0;var e=.5522848,f=c/2*e,g=d/2*e,h=a+c,i=b+d,j=a+c/2,k=b+d/2;this.beginPath(),this.moveTo(a,k),this.bezierCurveTo(a,k-g,j-f,b,j,b),this.bezierCurveTo(j+f,b,h,k-g,h,k),this.bezierCurveTo(h,k+g,j+f,i,j,i),this.bezierCurveTo(j-f,i,a,k+g,a,k),this.closePath()}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.hexagon=function(a,b,c,d){if(!(a&&b&&c&&d))return!0;var e=.225,f=1-e;this.beginPath(),this.moveTo(a+.5*c,b),this.lineTo(a,b+d*e),this.lineTo(a,b+d*f),this.lineTo(a+.5*c,b+d),this.lineTo(a+c,b+d*f),this.lineTo(a+c,b+d*e),this.lineTo(a+.5*c,b),this.closePath()}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.pentagon=function(a,b,c,d){return a&&b&&c&&d?(this.beginPath(),this.moveTo(a+c/2,b),this.lineTo(a,b+.4*d),this.lineTo(a+.2*c,b+d),this.lineTo(a+.8*c,b+d),this.lineTo(a+c,b+.4*d),this.lineTo(a+c/2,b),this.closePath(),void 0):!0}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.roundedRect=function(a,b,c,d,e){return a&&b&&c&&d?(e||(e=5),this.beginPath(),this.moveTo(a+e,b),this.lineTo(a+c-e,b),this.quadraticCurveTo(a+c,b,a+c,b+e),this.lineTo(a+c,b+d-e),this.quadraticCurveTo(a+c,b+d,a+c-e,b+d),this.lineTo(a+e,b+d),this.quadraticCurveTo(a,b+d,a,b+d-e),this.lineTo(a,b+e),this.quadraticCurveTo(a,b,a+e,b),this.closePath(),void 0):!0})}(); \ No newline at end of file
diff --git a/static/js/wpaint/plugins/shapes/src/wPaint.menu.main.shapes.js b/static/js/wpaint/plugins/shapes/src/wPaint.menu.main.shapes.js
new file mode 100644
index 0000000..1d4daeb
--- /dev/null
+++ b/static/js/wpaint/plugins/shapes/src/wPaint.menu.main.shapes.js
@@ -0,0 +1,207 @@
+(function ($) {
+ var img = 'plugins/shapes/img/icons-menu-main-shapes.png';
+
+ // extend menu
+ $.extend(true, $.fn.wPaint.menus.main.items, {
+ rectangle: {
+ group: 'shapes'
+ },
+ roundedRect: {
+ icon: 'activate',
+ group: 'shapes',
+ title: 'Rounded Rectangle',
+ img: img,
+ index: 0,
+ callback: function () { this.setMode('roundedRect'); }
+ },
+ square: {
+ icon: 'activate',
+ group: 'shapes',
+ title: 'Square',
+ img: img,
+ index: 1,
+ callback: function () { this.setMode('square'); }
+ },
+ roundedSquare: {
+ icon: 'activate',
+ group: 'shapes',
+ title: 'Rounded Square',
+ img: img,
+ index: 2,
+ callback: function () { this.setMode('roundedSquare'); }
+ },
+ diamond: {
+ icon: 'activate',
+ group: 'shapes',
+ title: 'Diamond',
+ img: img,
+ index: 4,
+ callback: function () { this.setMode('diamond'); }
+ },
+
+ ellipse: {
+ group: 'shapes2'
+ },
+ circle: {
+ icon: 'activate',
+ group: 'shapes2',
+ title: 'Circle',
+ img: img,
+ index: 3,
+ callback: function () { this.setMode('circle'); }
+ },
+ pentagon: {
+ icon: 'activate',
+ group: 'shapes2',
+ title: 'Pentagon',
+ img: img,
+ index: 5,
+ callback: function () { this.setMode('pentagon'); }
+ },
+ hexagon: {
+ icon: 'activate',
+ group: 'shapes2',
+ title: 'Hexagon',
+ img: img,
+ index: 6,
+ callback: function () { this.setMode('hexagon'); }
+ }
+ });
+
+ // extend functions
+ $.fn.wPaint.extend({
+ /****************************************
+ * roundedRect
+ ****************************************/
+ _drawRoundedRectDown: function (e) { this._drawShapeDown(e); },
+
+ _drawRoundedRectMove: function (e) {
+ this._drawShapeMove(e);
+
+ var radius = e.w > e.h ? e.h / e.w : e.w / e.h;
+
+ this.ctxTemp.roundedRect(e.x, e.y, e.w, e.h, Math.ceil(radius * (e.w * e.h * 0.001)));
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawRoundedRectUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * square
+ ****************************************/
+ _drawSquareDown: function (e) { this._drawShapeDown(e); },
+
+ _drawSquareMove: function (e) {
+ this._drawShapeMove(e);
+
+ var l = e.w > e.h ? e.h : e.w;
+
+ this.ctxTemp.rect(e.x, e.y, l, l);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawSquareUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * roundedSquare
+ ****************************************/
+ _drawRoundedSquareDown: function (e) { this._drawShapeDown(e); },
+
+ _drawRoundedSquareMove: function (e) {
+ this._drawShapeMove(e);
+
+ var l = e.w > e.h ? e.h : e.w;
+
+ this.ctxTemp.roundedRect(e.x, e.y, l, l, Math.ceil(l * l * 0.001));
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawRoundedSquareUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * diamond
+ ****************************************/
+ _drawDiamondDown: function (e) { this._drawShapeDown(e); },
+
+ _drawDiamondMove: function (e) {
+ this._drawShapeMove(e);
+
+ this.ctxTemp.diamond(e.x, e.y, e.w, e.h);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawDiamondUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * circle
+ ****************************************/
+ _drawCircleDown: function (e) { this._drawShapeDown(e); },
+
+ _drawCircleMove: function (e) {
+ this._drawShapeMove(e);
+
+ var l = e.w > e.h ? e.h : e.w;
+
+ this.ctxTemp.ellipse(e.x, e.y, l, l);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawCircleUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * pentagon
+ ****************************************/
+ _drawPentagonDown: function (e) { this._drawShapeDown(e); },
+
+ _drawPentagonMove: function (e) {
+ this._drawShapeMove(e);
+
+ this.ctxTemp.pentagon(e.x, e.y, e.w, e.h);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawPentagonUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ },
+
+ /****************************************
+ * hexagon
+ ****************************************/
+ _drawHexagonDown: function (e) { this._drawShapeDown(e); },
+
+ _drawHexagonMove: function (e) {
+ this._drawShapeMove(e);
+
+ this.ctxTemp.hexagon(e.x, e.y, e.w, e.h);
+ this.ctxTemp.stroke();
+ this.ctxTemp.fill();
+ },
+
+ _drawHexagonUp: function (e) {
+ this._drawShapeUp(e);
+ this._addUndo();
+ }
+ });
+})(jQuery);
diff --git a/static/js/wpaint/plugins/shapes/wPaint.menu.main.shapes.min.js b/static/js/wpaint/plugins/shapes/wPaint.menu.main.shapes.min.js
new file mode 100644
index 0000000..ac765bd
--- /dev/null
+++ b/static/js/wpaint/plugins/shapes/wPaint.menu.main.shapes.min.js
@@ -0,0 +1 @@
+/*! wPaint - v2.5.0 - 2014-03-01 */!function(a){var b="plugins/shapes/img/icons-menu-main-shapes.png";a.extend(!0,a.fn.wPaint.menus.main.items,{rectangle:{group:"shapes"},roundedRect:{icon:"activate",group:"shapes",title:"Rounded Rectangle",img:b,index:0,callback:function(){this.setMode("roundedRect")}},square:{icon:"activate",group:"shapes",title:"Square",img:b,index:1,callback:function(){this.setMode("square")}},roundedSquare:{icon:"activate",group:"shapes",title:"Rounded Square",img:b,index:2,callback:function(){this.setMode("roundedSquare")}},diamond:{icon:"activate",group:"shapes",title:"Diamond",img:b,index:4,callback:function(){this.setMode("diamond")}},ellipse:{group:"shapes2"},circle:{icon:"activate",group:"shapes2",title:"Circle",img:b,index:3,callback:function(){this.setMode("circle")}},pentagon:{icon:"activate",group:"shapes2",title:"Pentagon",img:b,index:5,callback:function(){this.setMode("pentagon")}},hexagon:{icon:"activate",group:"shapes2",title:"Hexagon",img:b,index:6,callback:function(){this.setMode("hexagon")}}}),a.fn.wPaint.extend({_drawRoundedRectDown:function(a){this._drawShapeDown(a)},_drawRoundedRectMove:function(a){this._drawShapeMove(a);var b=a.w>a.h?a.h/a.w:a.w/a.h;this.ctxTemp.roundedRect(a.x,a.y,a.w,a.h,Math.ceil(b*a.w*a.h*.001)),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawRoundedRectUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawSquareDown:function(a){this._drawShapeDown(a)},_drawSquareMove:function(a){this._drawShapeMove(a);var b=a.w>a.h?a.h:a.w;this.ctxTemp.rect(a.x,a.y,b,b),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawSquareUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawRoundedSquareDown:function(a){this._drawShapeDown(a)},_drawRoundedSquareMove:function(a){this._drawShapeMove(a);var b=a.w>a.h?a.h:a.w;this.ctxTemp.roundedRect(a.x,a.y,b,b,Math.ceil(b*b*.001)),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawRoundedSquareUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawDiamondDown:function(a){this._drawShapeDown(a)},_drawDiamondMove:function(a){this._drawShapeMove(a),this.ctxTemp.diamond(a.x,a.y,a.w,a.h),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawDiamondUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawCircleDown:function(a){this._drawShapeDown(a)},_drawCircleMove:function(a){this._drawShapeMove(a);var b=a.w>a.h?a.h:a.w;this.ctxTemp.ellipse(a.x,a.y,b,b),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawCircleUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawPentagonDown:function(a){this._drawShapeDown(a)},_drawPentagonMove:function(a){this._drawShapeMove(a),this.ctxTemp.pentagon(a.x,a.y,a.w,a.h),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawPentagonUp:function(a){this._drawShapeUp(a),this._addUndo()},_drawHexagonDown:function(a){this._drawShapeDown(a)},_drawHexagonMove:function(a){this._drawShapeMove(a),this.ctxTemp.hexagon(a.x,a.y,a.w,a.h),this.ctxTemp.stroke(),this.ctxTemp.fill()},_drawHexagonUp:function(a){this._drawShapeUp(a),this._addUndo()}})}(jQuery),!function(){window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.diamond=function(a,b,c,d){return a&&b&&c&&d?(this.beginPath(),this.moveTo(a+.5*c,b),this.lineTo(a,b+.5*d),this.lineTo(a+.5*c,b+d),this.lineTo(a+c,b+.5*d),this.lineTo(a+.5*c,b),void this.closePath()):!0}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.ellipse=function(a,b,c,d){if(!(a&&b&&c&&d))return!0;var e=.5522848,f=c/2*e,g=d/2*e,h=a+c,i=b+d,j=a+c/2,k=b+d/2;this.beginPath(),this.moveTo(a,k),this.bezierCurveTo(a,k-g,j-f,b,j,b),this.bezierCurveTo(j+f,b,h,k-g,h,k),this.bezierCurveTo(h,k+g,j+f,i,j,i),this.bezierCurveTo(j-f,i,a,k+g,a,k),this.closePath()}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.hexagon=function(a,b,c,d){if(!(a&&b&&c&&d))return!0;var e=.225,f=1-e;this.beginPath(),this.moveTo(a+.5*c,b),this.lineTo(a,b+d*e),this.lineTo(a,b+d*f),this.lineTo(a+.5*c,b+d),this.lineTo(a+c,b+d*f),this.lineTo(a+c,b+d*e),this.lineTo(a+.5*c,b),this.closePath()}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.pentagon=function(a,b,c,d){return a&&b&&c&&d?(this.beginPath(),this.moveTo(a+c/2,b),this.lineTo(a,b+.4*d),this.lineTo(a+.2*c,b+d),this.lineTo(a+.8*c,b+d),this.lineTo(a+c,b+.4*d),this.lineTo(a+c/2,b),void this.closePath()):!0}),window.CanvasRenderingContext2D&&(CanvasRenderingContext2D.prototype.roundedRect=function(a,b,c,d,e){return a&&b&&c&&d?(e||(e=5),this.beginPath(),this.moveTo(a+e,b),this.lineTo(a+c-e,b),this.quadraticCurveTo(a+c,b,a+c,b+e),this.lineTo(a+c,b+d-e),this.quadraticCurveTo(a+c,b+d,a+c-e,b+d),this.lineTo(a+e,b+d),this.quadraticCurveTo(a,b+d,a,b+d-e),this.lineTo(a,b+e),this.quadraticCurveTo(a,b,a+e,b),void this.closePath()):!0})}(); \ No newline at end of file
diff --git a/static/js/wpaint/plugins/text/img/icons-menu-text.png b/static/js/wpaint/plugins/text/img/icons-menu-text.png
new file mode 100644
index 0000000..d7bed8c
--- /dev/null
+++ b/static/js/wpaint/plugins/text/img/icons-menu-text.png
Binary files differ
diff --git a/static/js/wpaint/plugins/text/src/wPaint.menu.text.js b/static/js/wpaint/plugins/text/src/wPaint.menu.text.js
new file mode 100644
index 0000000..5a15ac0
--- /dev/null
+++ b/static/js/wpaint/plugins/text/src/wPaint.menu.text.js
@@ -0,0 +1,227 @@
+(function ($) {
+
+ // setup menu
+ $.fn.wPaint.menus.text = {
+ img: 'plugins/text/img/icons-menu-text.png',
+ items: {
+ bold: {
+ icon: 'toggle',
+ title: 'Bold',
+ index: 0,
+ callback: function (toggle) { this.setFontBold(toggle); }
+ },
+ italic: {
+ icon: 'toggle',
+ title: 'Italic',
+ index: 1,
+ callback: function (toggle) { this.setFontItalic(toggle); }
+ },
+ /*underline: {
+ icon: 'toggle',
+ title: 'Undelrine',
+ index: 2,
+ callback: function (toggle) { this.setFontUnderline(toggle); }
+ },*/
+ fontSize: {
+ title: 'Font Size',
+ icon: 'select',
+ range: [8, 9, 10, 12, 14, 16, 20, 24, 30],
+ value: 12,
+ callback: function (size) { this.setFontSize(size); }
+ },
+ fontFamily: {
+ icon: 'select',
+ title: 'Font Family',
+ range: ['Arial', 'Courier', 'Times', 'Verdana'],
+ useRange: true,
+ value: 'Arial',
+ callback: function (family) { this.setFontFamily(family); }
+ }
+ }
+ };
+
+ // add icon to main menu
+ $.fn.wPaint.menus.main.items.text = {
+ icon: 'menu',
+ after: 'pencil',
+ title: 'Text',
+ index: 7,
+ callback: function () { this.setMode('text'); }
+ };
+
+ // extend defaults
+ $.extend($.fn.wPaint.defaults, {
+ fontSize : '12', // current font size for text input
+ fontFamily : 'Arial', // active font family for text input
+ fontBold : false, // text input bold enable/disable
+ fontItalic : false, // text input italic enable/disable
+ fontUnderline : false // text input italic enable/disable
+ });
+
+ // extend functions
+ $.fn.wPaint.extend({
+ generate: function () {
+ this.$textCalc = $('<div></div>').hide();
+
+ // make sure clicking on the text-tnput doesn't trigger another textInput
+ this.$textInput = $('<textarea class="wPaint-text-input" spellcheck="false"></textarea>')
+ .on('mousedown', this._stopPropagation)
+ .css({position: 'absolute'})
+ .hide();
+
+ $('body').append(this.$textCalc);
+ this.$el.append(this.$textInput);
+
+ this.menus.all.text = this._createMenu('text');
+ },
+
+ _init: function () {
+ var _this = this;
+
+ function inputClick() {
+ _this._drawTextIfNotEmpty();
+ _this.$textInput.hide();
+ _this.$canvasTemp.hide();
+ }
+
+ // in case we click on another element while typing - just auto set the text
+ for (var i in this.menus.all) {
+ this.menus.all[i].$menu
+ .on('click', inputClick)
+ .on('mousedown', this._stopPropagation);
+ }
+
+ // same idea here for clicking outside of the canvas area
+ $(document).on('mousedown', inputClick);
+ },
+
+ /****************************************
+ * setters
+ ****************************************/
+ setFillStyle: function (fillStyle) {
+ this.$textInput.css('color', fillStyle);
+ },
+
+ setFontSize: function (size) {
+ this.options.fontSize = parseInt(size, 10);
+ this._setFont({fontSize: size + 'px', lineHeight: size + 'px'});
+ this.menus.all.text._setSelectValue('fontSize', size);
+ },
+
+ setFontFamily: function (family) {
+ this.options.fontFamily = family;
+ this._setFont({fontFamily: family});
+ this.menus.all.text._setSelectValue('fontFamily', family);
+ },
+
+ setFontBold: function (bold) {
+ this.options.fontBold = bold;
+ this._setFont({fontWeight: (bold ? 'bold' : '')});
+ },
+
+ setFontItalic: function (italic) {
+ this.options.fontItalic = italic;
+ this._setFont({fontStyle: (italic ? 'italic' : '')});
+ },
+
+ setFontUnderline: function (underline) {
+ this.options.fontUnderline = underline;
+ this._setFont({fontWeight: (underline ? 'underline' : '')});
+ },
+
+ _setFont: function (css) {
+ this.$textInput.css(css);
+ this.$textCalc.css(css);
+ },
+
+ /****************************************
+ * Text
+ ****************************************/
+ _drawTextDown: function (e) {
+ this._drawTextIfNotEmpty();
+ this._drawShapeDown(e, 1);
+
+ this.$textInput
+ .css({left: e.pageX - 1, top: e.pageY - 1, width: 0, height: 0})
+ .show().focus();
+ },
+
+ _drawTextMove: function (e) {
+ this._drawShapeMove(e, 1);
+
+ this.$textInput.css({left: e.left - 1, top: e.top - 1, width: e.width, height: e.height});
+ },
+
+ _drawTextIfNotEmpty: function () {
+ if (this.$textInput.val() !== '') { this._drawText(); }
+ },
+
+ // just draw text - don't want to trigger up here since we are just copying text from input box here
+ _drawText: function () {
+ var fontString = '',
+ lines = this.$textInput.val().split('\n'),
+ linesNew = [],
+ textInputWidth = this.$textInput.width() - 2,
+ width = 0,
+ lastj = 0,
+ offset = this.$textInput.position(),
+ left = offset.left + 1,
+ top = offset.top + 1,
+ //underlineOffset = 0,
+ i, ii, j, jj;
+
+ if (this.options.fontItalic) { fontString += 'italic '; }
+ //if(this.settings.fontUnderline) { fontString += 'underline '; }
+ if (this.options.fontBold) { fontString += 'bold '; }
+
+ fontString += this.options.fontSize + 'px ' + this.options.fontFamily;
+
+ for (i = 0, ii = lines.length; i < ii; i++) {
+ this.$textCalc.html('');
+ lastj = 0;
+
+ for (j = 0, jj = lines[0].length; j < jj; j++) {
+ width = this.$textCalc.append(lines[i][j]).width();
+
+ if (width > textInputWidth) {
+ linesNew.push(lines[i].substring(lastj, j));
+ lastj = j;
+ this.$textCalc.html(lines[i][j]);
+ }
+ }
+
+ if (lastj !== j) { linesNew.push(lines[i].substring(lastj, j)); }
+ }
+
+ lines = this.$textInput.val(linesNew.join('\n')).val().split('\n');
+
+ for (i = 0, ii = lines.length; i < ii; i++) {
+ this.ctx.fillStyle = this.options.fillStyle;
+ this.ctx.textBaseline = 'top';
+ this.ctx.font = fontString;
+ this.ctx.fillText(lines[i], left, top);
+
+ top += this.options.fontSize;
+
+ /*if(lines[i] !== '' && this.options.fontTypeUnderline) {
+ width = this.$textCalc.html(lines[i]).width();
+
+ //manually set pixels for underline since to avoid antialiasing 1px issue, and lack of support for underline in canvas
+ var imgData = this.ctx.getImageData(0, top+underlineOffset, width, 1);
+
+ for (j=0; j<imgData.width*imgData.height*4; j+=4) {
+ imgData.data[j] = parseInt(this.options.fillStyle.substring(1,3), 16);
+ imgData.data[j+1] = parseInt(this.options.fillStyle.substring(3,5), 16);
+ imgData.data[j+2] = parseInt(this.options.fillStyle.substring(5,7), 16);
+ imgData.data[j+3] = 255;
+ }
+
+ this.ctx.putImageData(imgData, left, top+underlineOffset);
+ }*/
+ }
+
+ this.$textInput.val('');
+ this._addUndo();
+ }
+ });
+})(jQuery);
diff --git a/static/js/wpaint/plugins/text/wPaint.menu.text.min.js b/static/js/wpaint/plugins/text/wPaint.menu.text.min.js
new file mode 100644
index 0000000..6cd1f3d
--- /dev/null
+++ b/static/js/wpaint/plugins/text/wPaint.menu.text.min.js
@@ -0,0 +1 @@
+/*! wPaint - v2.5.0 - 2014-03-01 */!function(a){a.fn.wPaint.menus.text={img:"plugins/text/img/icons-menu-text.png",items:{bold:{icon:"toggle",title:"Bold",index:0,callback:function(a){this.setFontBold(a)}},italic:{icon:"toggle",title:"Italic",index:1,callback:function(a){this.setFontItalic(a)}},fontSize:{title:"Font Size",icon:"select",range:[8,9,10,12,14,16,20,24,30],value:12,callback:function(a){this.setFontSize(a)}},fontFamily:{icon:"select",title:"Font Family",range:["Arial","Courier","Times","Verdana"],useRange:!0,value:"Arial",callback:function(a){this.setFontFamily(a)}}}},a.fn.wPaint.menus.main.items.text={icon:"menu",after:"pencil",title:"Text",index:7,callback:function(){this.setMode("text")}},a.extend(a.fn.wPaint.defaults,{fontSize:"12",fontFamily:"Arial",fontBold:!1,fontItalic:!1,fontUnderline:!1}),a.fn.wPaint.extend({generate:function(){this.$textCalc=a("<div></div>").hide(),this.$textInput=a('<textarea class="wPaint-text-input" spellcheck="false"></textarea>').on("mousedown",this._stopPropagation).css({position:"absolute"}).hide(),a("body").append(this.$textCalc),this.$el.append(this.$textInput),this.menus.all.text=this._createMenu("text")},_init:function(){function b(){c._drawTextIfNotEmpty(),c.$textInput.hide(),c.$canvasTemp.hide()}var c=this;for(var d in this.menus.all)this.menus.all[d].$menu.on("click",b).on("mousedown",this._stopPropagation);a(document).on("mousedown",b)},setFillStyle:function(a){this.$textInput.css("color",a)},setFontSize:function(a){this.options.fontSize=parseInt(a,10),this._setFont({fontSize:a+"px",lineHeight:a+"px"}),this.menus.all.text._setSelectValue("fontSize",a)},setFontFamily:function(a){this.options.fontFamily=a,this._setFont({fontFamily:a}),this.menus.all.text._setSelectValue("fontFamily",a)},setFontBold:function(a){this.options.fontBold=a,this._setFont({fontWeight:a?"bold":""})},setFontItalic:function(a){this.options.fontItalic=a,this._setFont({fontStyle:a?"italic":""})},setFontUnderline:function(a){this.options.fontUnderline=a,this._setFont({fontWeight:a?"underline":""})},_setFont:function(a){this.$textInput.css(a),this.$textCalc.css(a)},_drawTextDown:function(a){this._drawTextIfNotEmpty(),this._drawShapeDown(a,1),this.$textInput.css({left:a.pageX-1,top:a.pageY-1,width:0,height:0}).show().focus()},_drawTextMove:function(a){this._drawShapeMove(a,1),this.$textInput.css({left:a.left-1,top:a.top-1,width:a.width,height:a.height})},_drawTextIfNotEmpty:function(){""!==this.$textInput.val()&&this._drawText()},_drawText:function(){var a,b,c,d,e="",f=this.$textInput.val().split("\n"),g=[],h=this.$textInput.width()-2,i=0,j=0,k=this.$textInput.position(),l=k.left+1,m=k.top+1;for(this.options.fontItalic&&(e+="italic "),this.options.fontBold&&(e+="bold "),e+=this.options.fontSize+"px "+this.options.fontFamily,a=0,b=f.length;b>a;a++){for(this.$textCalc.html(""),j=0,c=0,d=f[0].length;d>c;c++)i=this.$textCalc.append(f[a][c]).width(),i>h&&(g.push(f[a].substring(j,c)),j=c,this.$textCalc.html(f[a][c]));j!==c&&g.push(f[a].substring(j,c))}for(f=this.$textInput.val(g.join("\n")).val().split("\n"),a=0,b=f.length;b>a;a++)this.ctx.fillStyle=this.options.fillStyle,this.ctx.textBaseline="top",this.ctx.font=e,this.ctx.fillText(f[a],l,m),m+=this.options.fontSize;this.$textInput.val(""),this._addUndo()}})}(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/src/wPaint.css b/static/js/wpaint/src/wPaint.css
new file mode 100644
index 0000000..7bc0a70
--- /dev/null
+++ b/static/js/wpaint/src/wPaint.css
@@ -0,0 +1,348 @@
+/**********************************************************************
+ * Layout
+ **********************************************************************/
+
+/*** menu ***/
+.wPaint-menu {
+ position: absolute !important;
+ display: inline-block;
+ line-height: 0px;
+ z-index: 99;
+}
+.wPaint-menu-behind {
+ z-index: 98;
+}
+.wPaint-menu-holder {
+ position: relative;
+ margin: 0 1px 1px 0;
+}
+.wPaint-menu-handle {
+ display: inline-block;
+}
+.wPaint-menu-icon {
+ position: relative;
+ vertical-align: top;
+}
+.wPaint-menu-icon-img {
+ position: relative;
+ display: inline-block;
+ background-repeat: no-repeat;
+ overflow: hidden;
+}
+/*** select ***/
+.wPaint-menu-select-holder{
+ position: absolute;
+ left: 1px;
+ z-index: 10;
+ overflow: hidden;
+}
+.wPaint-menu-select {
+ position: relative;
+ text-align: center;
+ overflow-y: scroll;
+ z-index: 100;
+}
+.wPaint-menu-select-option.first {
+ border-top: 0px;
+}
+/*** alignment ***/
+.wPaint-menu-alignment-horizontal .wPaint-menu-icon {
+ display: inline-block;
+}
+.wPaint-menu-alignment-vertical .wPaint-menu-icon {
+ display: block;
+}
+/*** status ***/
+.wPaint-status {
+ position: absolute;
+ display: none;
+ right: 0px;
+ bottom: 0px;
+}
+/*** modal ***/
+.wPaint-modal-bg {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 100%;
+ height: 100%;
+}
+.wPaint-modal {
+ position: absolute;
+ display: inline-block;
+}
+.wPaint-modal-holder {
+ display: inline-block;
+ overflow: hidden;
+}
+.wPaint-modal-content {
+ overflow-y: scroll;
+ width: 100%;
+ height: 100%;
+}
+.wPaint-modal-close {
+ position: absolute;
+}
+/*** text input ***/
+.wPaint-text-input{
+ margin: 0px;
+ padding: 0px;
+ outline-width: 0;
+ word-wrap: break-word;
+ overflow: hidden;
+}
+/*** file load ***/
+.wPaint-modal-img-holder {
+ line-height: 0px;
+}
+.wPaint-modal-img {
+ display: inline-block;
+}
+
+/**********************************************************************
+ * Generic Appearance
+ *
+ * Probably don't need to change these styles but can overwrite
+ * whatever is necessary.
+ **********************************************************************/
+
+/*** menu ***/
+.wPaint-menu-holder {
+ border-style: solid;
+ border-width: 1px;
+ box-shadow:3px 3px 5px #555555;
+}
+.wPaint-menu-handle {
+ cursor: pointer;
+}
+.wPaint-menu-icon {
+ border-style: solid;
+ border-width: 1px;
+ cursor: pointer;
+}
+.wPaint-menu-icon.disabled {
+ cursor: default;
+}
+.wPaint-menu-icon.disabled .wPaint-menu-icon-img {
+ opacity: 0.3;
+}
+.wPaint-menu-icon-img {
+ font-family: verdana;
+ font-weight: bold;
+ text-align: center;
+}
+/*** select ***/
+.wPaint-menu-select-holder {
+ border-style: solid;
+ border-width: 1px;
+ box-shadow: 1px 1px 2px #666;
+}
+.wPaint-menu-select {
+ font-family: verdana;
+ text-align: center;
+}
+.wPaint-menu-select-option {
+ border-top-style: solid;
+ border-top-width: 1px;
+ cursor: pointer;
+}
+.wPaint-menu-icon-select-img {
+ background-repeat: no-repeat;
+}
+.wPaint-menu-icon-group-arrow {
+ position: absolute;
+ right: 1px;
+ bottom: 1px;
+}
+/*** alignment ***/
+.wPaint-menu-alignment-horizontal .wPaint-menu-handle {
+ border-right-style: solid;
+ border-right-width: 1px;
+}
+.wPaint-menu-alignment-vertical .wPaint-menu-handle {
+ border-bottom-style: solid;
+ border-bottom-width: 1px;
+}
+/*** status ***/
+.wPaint-status {
+ font-size: 10px;
+ font-family: verdana;
+ line-height: 10px;
+ height: 10px;
+ background-color: #3a3a3a;
+ color: #f0f0f0;
+ padding: 5px;
+ opacity: 0.5;
+}
+/*** modal ***/
+.wPaint-modal-bg {
+ background-color: #3a3a3a;
+ opacity: 0.8;
+}
+.wPaint-modal-holder {
+ height: 100px;
+ box-shadow: 3px 3px 5px #555555;
+ border-radius: 5px;
+ border-style: solid;
+ border-width: 2px;
+ cursor: default;
+}
+.wPaint-modal-close {
+ right: -7px;
+ top: -7px;
+ border-radius: 10px;
+ font-size: 8px;
+ line-height: 14px;
+ padding: 0 4px;
+ font-weight:bold;
+ border-style: solid;
+ border-width: 2px;
+ cursor: pointer;
+}
+/*** text input ***/
+.wPaint-text-input{
+ border: dotted #0000FF 1px;
+ background: none;
+}
+/*** file load ***/
+.wPaint-modal-img-holder {
+ border: solid #333 1px;
+ border-radius: 5px;
+ margin: 3px;
+ padding: 2px;
+ cursor: pointer;
+}
+.wPaint-modal-img {
+ width: 100px;
+ border-radius: 4px;
+ margin-bottom: 0px;
+}
+
+/**********************************************************************
+ * Size - standard theme
+ **********************************************************************/
+
+/*** menu ***/
+.wPaint-theme-standard .wPaint-menu-holder {
+ border-radius: 7px;
+}
+.wPaint-theme-standard .wPaint-menu-select-holder {
+ border-radius: 5px;
+}
+.wPaint-theme-standard .wPaint-menu-icon {
+ border-radius: 7px;
+}
+.wPaint-theme-standard .wPaint-menu-icon-img {
+ margin: 6px 5px 5px 6px;
+ width: 18px;
+ height: 18px;
+ line-height: 18px;
+ font-size: 12px;
+}
+.wPaint-theme-standard .wPaint-menu-colorpicker .wPaint-menu-icon-img {
+ margin: 3px 2px 2px 3px;
+ width: 24px;
+ height: 24px;
+ border-radius: 5px;
+}
+/*** select ***/
+.wPaint-theme-standard .wPaint-menu-icon-group .wPaint-menu-select-option {
+ padding: 4px;
+}
+.wPaint-theme-standard .wPaint-menu-icon-group-arrow {
+ width: 5px;
+ height: 3px;
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAADCAYAAABbNsX4AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABZ0RVh0Q3JlYXRpb24gVGltZQAwOC8xMS8xMyj8hykAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAKElEQVQImV3IwQ0AMAyDQKerspZ3pa9IVXmdGMB8nbbzjrYTNWoA1xeQ3RPyxUyE/gAAAABJRU5ErkJggg==');
+}
+.wPaint-theme-standard .wPaint-menu-select {
+ line-height: 10px;
+ font-size: 10px;
+ max-height: 136px;
+}
+.wPaint-theme-standard .wPaint-menu-select-option {
+ max-width: 50px;
+ padding: 4px 7px;
+}
+.wPaint-theme-standard .wPaint-menu-icon-select-img {
+ width: 18px;
+ height: 18px;
+}
+/* horizontal */
+.wPaint-theme-standard .wPaint-menu-alignment-horizontal.wPaint-menu-nohandle .wPaint-menu-holder {
+ padding-left: 4px;
+}
+.wPaint-theme-standard .wPaint-menu-alignment-horizontal .wPaint-menu-icon {
+ margin: 4px 5px 4px 0;
+}
+.wPaint-theme-standard .wPaint-menu-alignment-horizontal .wPaint-menu-handle {
+ width: 30px;
+ height: 39px;
+ margin-right: 5px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+}
+/* vertical */
+.wPaint-theme-standard .wPaint-menu-alignment-vertical.wPaint-menu-nohandle .wPaint-menu-holder {
+ padding-top: 4px;
+}
+.wPaint-theme-standard .wPaint-menu-alignment-vertical .wPaint-menu-icon {
+ margin: 0 4px 5px 4px;
+}
+.wPaint-theme-standard .wPaint-menu-alignment-vertical .wPaint-menu-handle {
+ width: 39px;
+ height: 30px;
+ margin-bottom: 5px;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+}
+
+/**********************************************************************
+ * Style - classic theme
+ **********************************************************************/
+
+/*** menu ***/
+.wPaint-theme-classic .wPaint-menu-holder {
+ border-color: #dadada;
+ background-color: #f0f0f0;
+}
+.wPaint-theme-classic .wPaint-menu-handle {
+ background-color: #dadada;
+ box-shadow: inset 1px 1px 3px #FFF;
+ border-color: #dadada;
+}
+.wPaint-theme-classic .wPaint-menu-icon {
+ border-color: #b9b9b9;
+ background-color: #b9b9b9;
+ box-shadow: inset 2px 2px 3px #eee, 1px 1px 2px #666;
+}
+.wPaint-theme-classic .wPaint-menu-icon.hover,
+.wPaint-theme-classic .wPaint-menu-icon.active {
+ border-color: #99ccff;
+ background-color: #aaccff;
+}
+.wPaint-theme-classic .wPaint-menu-icon-img {
+ color: #696969;
+}
+/*** select ***/
+.wPaint-theme-classic .wPaint-menu-select-holder {
+ border-color: #CACACA;
+}
+.wPaint-theme-classic .wPaint-menu-select {
+ color: #494949;
+}
+.wPaint-theme-classic .wPaint-menu-select-option {
+ box-shadow: inset 2px 2px 3px #fff;
+ border-top-color: #CACACA;
+ background-color: #F0F0F0;
+}
+.wPaint-theme-classic .wPaint-menu-select-option:hover {
+ box-shadow: inset 1px 1px 1px #fff;
+ background-color: #99ccff;
+ color: #f0f0f0;
+}
+/*** modal ***/
+.wPaint-theme-classic .wPaint-modal-close,
+.wPaint-theme-classic .wPaint-modal-holder {
+ border-color: #3a3a3a;
+ background-color: #f0f0f0;
+}
diff --git a/static/js/wpaint/src/wPaint.js b/static/js/wpaint/src/wPaint.js
new file mode 100644
index 0000000..9717f6d
--- /dev/null
+++ b/static/js/wpaint/src/wPaint.js
@@ -0,0 +1,1181 @@
+(function ($) {
+ 'use strict';
+
+ /************************************************************************
+ * Paint class
+ ************************************************************************/
+ function Paint(el, options) {
+ this.$el = $(el);
+ this.options = options;
+ this.init = false;
+
+ this.menus = {primary: null, active: null, all: {}};
+ this.previousMode = null;
+ this.width = this.$el.width();
+ this.height = this.$el.height();
+
+ this.ctxBgResize = false;
+ this.ctxResize = false;
+
+ this.generate();
+ this._init();
+ }
+
+ Paint.prototype = {
+ generate: function () {
+ if (this.init) { return this; }
+
+ var _this = this;
+
+ // automatically appends each canvas
+ // also returns the jQuery object so we can chain events right off the function call.
+ // for the tempCanvas we will be setting some extra attributes but don't won't matter
+ // as they will be reset on mousedown anyway.
+ function createCanvas(name) {
+ var newName = (name ? name.capitalize() : ''),
+ canvasName = 'canvas' + newName,
+ ctxName = 'ctx' + newName;
+
+ _this[canvasName] = document.createElement('canvas');
+ _this[ctxName] = _this[canvasName].getContext('2d');
+ _this['$' + canvasName] = $(_this[canvasName]);
+
+ _this['$' + canvasName]
+ .attr('class', 'wPaint-canvas' + (name ? '-' + name : ''))
+ .attr('width', _this.width + 'px')
+ .attr('height', _this.height + 'px')
+ .css({position: 'absolute', left: 0, top: 0});
+
+ _this.$el.append(_this['$' + canvasName]);
+
+ return _this['$' + canvasName];
+ }
+
+ // event functions
+ function canvasMousedown(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ _this.draw = true;
+ e.canvasEvent = 'down';
+ _this._closeSelectBoxes();
+ _this._callShapeFunc.apply(_this, [e]);
+ }
+
+ function documentMousemove(e) {
+ if (_this.draw) {
+ e.canvasEvent = 'move';
+ _this._callShapeFunc.apply(_this, [e]);
+ }
+ }
+
+ function documentMouseup(e) {
+
+ //make sure we are in draw mode otherwise this will fire on any mouse up.
+ if (_this.draw) {
+ _this.draw = false;
+ e.canvasEvent = 'up';
+ _this._callShapeFunc.apply(_this, [e]);
+ }
+ }
+
+ // create bg canvases
+ createCanvas('bg');
+
+ // create drawing canvas
+ createCanvas('')
+ .on('mousedown', canvasMousedown)
+ .bindMobileEvents();
+
+ // create temp canvas for drawing shapes temporarily
+ // before transfering to main canvas
+ createCanvas('temp').hide();
+
+ // event handlers for drawing
+ $(document)
+ .on('mousemove', documentMousemove)
+ .on('mousedown', $.proxy(this._closeSelectBoxes, this))
+ .on('mouseup', documentMouseup);
+
+ // we will need to preset theme to get proper dimensions
+ // when creating menus which will be appended after this
+ this.setTheme(this.options.theme);
+ },
+
+ _init: function () {
+ var index = null,
+ setFuncName = null;
+
+ this.init = true;
+
+ // run any set functions if they exist
+ for (index in this.options) {
+ setFuncName = 'set' + index.capitalize();
+ if (this[setFuncName]) { this[setFuncName](this.options[index]); }
+ }
+
+ // fix menus
+ this._fixMenus();
+
+ // initialize active menu button
+ this.menus.primary._getIcon(this.options.mode).trigger('click');
+ },
+
+ resize: function () {
+ var bg = this.getBg(),
+ image = this.getImage();
+
+ this.width = this.$el.width();
+ this.height = this.$el.height();
+
+ this.canvasBg.width = this.width;
+ this.canvasBg.height = this.height;
+ this.canvas.width = this.width;
+ this.canvas.height = this.height;
+
+ if (this.ctxBgResize === false) {
+ this.ctxBgResize = true;
+ this.setBg(bg, true);
+ }
+
+ if (this.ctxResize === false) {
+ this.ctxResize = true;
+ this.setImage(image, '', true, true);
+ }
+ },
+
+ /************************************
+ * setters
+ ************************************/
+ setTheme: function (theme) {
+ var i, ii;
+
+ theme = theme.split(' ');
+
+ // remove anything beginning with "wPaint-theme-" first
+ this.$el.attr('class', (this.$el.attr('class') || '').replace(/wPaint-theme-.+\s|wPaint-theme-.+$/, ''));
+
+ // add each theme
+ for (i = 0, ii = theme.length; i < ii; i++) {
+ this.$el.addClass('wPaint-theme-' + theme[i]);
+ }
+ },
+
+ setMode: function (mode) {
+ this.setCursor(mode);
+ this.previousMode = this.options.mode;
+ this.options.mode = mode;
+ },
+
+ setImage: function (img, ctxType, resize, notUndo) {
+ if (!img) { return true; }
+
+ var _this = this,
+ myImage = null,
+ ctx = '';
+
+ function loadImage() {
+ var ratio = 1, xR = 0, yR = 0, x = 0, y = 0, w = myImage.width, h = myImage.height;
+
+ if (!resize) {
+ // get width/height
+ if (myImage.width > _this.width || myImage.height > _this.height || _this.options.imageStretch) {
+ xR = _this.width / myImage.width;
+ yR = _this.height / myImage.height;
+
+ ratio = xR < yR ? xR : yR;
+
+ w = myImage.width * ratio;
+ h = myImage.height * ratio;
+ }
+
+ // get left/top (centering)
+ x = (_this.width - w) / 2;
+ y = (_this.height - h) / 2;
+ }
+
+ ctx.clearRect(0, 0, _this.width, _this.height);
+ ctx.drawImage(myImage, x, y, w, h);
+
+ _this[ctxType + 'Resize'] = false;
+
+ // Default is to run the undo.
+ // If it's not to be run set it the flag to true.
+ if (!notUndo) {
+ _this._addUndo();
+ }
+ }
+
+ ctxType = 'ctx' + (ctxType || '').capitalize();
+ ctx = this[ctxType];
+
+ if (window.rgbHex(img)) {
+ ctx.clearRect(0, 0, this.width, this.height);
+ ctx.fillStyle = img;
+ ctx.rect(0, 0, this.width, this.height);
+ ctx.fill();
+ }
+ else {
+ myImage = new Image();
+ myImage.src = img.toString();
+ $(myImage).load(loadImage);
+ }
+ },
+
+ setBg: function (img, resize) {
+ if (!img) { return true; }
+
+ this.setImage(img, 'bg', resize, true);
+ },
+
+ setCursor: function (cursor) {
+ cursor = $.fn.wPaint.cursors[cursor] || $.fn.wPaint.cursors['default'];
+
+ this.$el.css('cursor', 'url("' + this.options.path + cursor.path + '") ' + cursor.left + ' ' + cursor.top + ', default');
+ },
+
+ setMenuOrientation: function (orientation) {
+ $.each(this.menus.all, function (i, menu) {
+ menu.options.aligment = orientation;
+ menu.setAlignment(orientation);
+ });
+ },
+
+ getImage: function (withBg) {
+ var canvasSave = document.createElement('canvas'),
+ ctxSave = canvasSave.getContext('2d');
+
+ withBg = withBg === false ? false : true;
+
+ $(canvasSave)
+ .css({display: 'none', position: 'absolute', left: 0, top: 0})
+ .attr('width', this.width)
+ .attr('height', this.height);
+
+ if (withBg) { ctxSave.drawImage(this.canvasBg, 0, 0); }
+ ctxSave.drawImage(this.canvas, 0, 0);
+
+ return canvasSave.toDataURL();
+ },
+
+ getBg: function () {
+ return this.canvasBg.toDataURL();
+ },
+
+ /************************************
+ * prompts
+ ************************************/
+ _displayStatus: function (msg) {
+ var _this = this;
+
+ if (!this.$status) {
+ this.$status = $('<div class="wPaint-status"></div>');
+ this.$el.append(this.$status);
+ }
+
+ this.$status.html(msg);
+ clearTimeout(this.displayStatusTimer);
+
+ this.$status.fadeIn(500, function () {
+ _this.displayStatusTimer = setTimeout(function () { _this.$status.fadeOut(500); }, 1500);
+ });
+ },
+
+ _showModal: function ($content) {
+ var _this = this,
+ $bg = this.$el.children('.wPaint-modal-bg'),
+ $modal = this.$el.children('.wPaint-modal');
+
+ function modalFadeOut() {
+ $bg.remove();
+ $modal.remove();
+ _this._createModal($content);
+ }
+
+ if ($bg.length) {
+ $modal.fadeOut(500, modalFadeOut);
+ }
+ else {
+ this._createModal($content);
+ }
+ },
+
+ _createModal: function ($content) {
+ $content = $('<div class="wPaint-modal-content"></div>').append($content.children());
+
+ var $bg = $('<div class="wPaint-modal-bg"></div>'),
+ $modal = $('<div class="wPaint-modal"></div>'),
+ $holder = $('<div class="wPaint-modal-holder"></div>'),
+ $close = $('<div class="wPaint-modal-close">X</div>');
+
+ function modalClick() {
+ $modal.fadeOut(500, modalFadeOut);
+ }
+
+ function modalFadeOut() {
+ $bg.remove();
+ $modal.remove();
+ }
+
+ $close.on('click', modalClick);
+ $modal.append($holder.append($content)).append($close);
+ this.$el.append($bg).append($modal);
+
+ $modal.css({
+ left: (this.$el.outerWidth() / 2) - ($modal.outerWidth(true) / 2),
+ top: (this.$el.outerHeight() / 2) - ($modal.outerHeight(true) / 2)
+ });
+
+ $modal.fadeIn(500);
+ },
+
+ /************************************
+ * menu helpers
+ ************************************/
+ _createMenu: function (name, options) {
+ options = options || {};
+ options.alignment = this.options.menuOrientation;
+ options.handle = this.options.menuHandle;
+
+ return new Menu(this, name, options);
+ },
+
+ _fixMenus: function () {
+ var _this = this,
+ $selectHolder = null;
+
+ function selectEach(i, el) {
+ var $el = $(el),
+ $select = $el.clone();
+
+ $select.appendTo(_this.$el);
+
+ if ($select.outerHeight() === $select.get(0).scrollHeight) {
+ $el.css({overflowY: 'auto'});
+ }
+
+ $select.remove();
+ }
+
+ // TODO: would be nice to do this better way
+ // for some reason when setting overflowY:auto with dynamic content makes the width act up
+ for (var key in this.menus.all) {
+ $selectHolder = _this.menus.all[key].$menu.find('.wPaint-menu-select-holder');
+ if ($selectHolder.length) { $selectHolder.children().each(selectEach); }
+ }
+ },
+
+ _closeSelectBoxes: function (item) {
+ var key, $selectBoxes;
+
+ for (key in this.menus.all) {
+ $selectBoxes = this.menus.all[key].$menuHolder.children('.wPaint-menu-icon-select');
+
+ // hide any open select menus excluding the current menu
+ // this is to avoid the double toggle since there are some
+ // other events running here
+ if (item) { $selectBoxes = $selectBoxes.not('.wPaint-menu-icon-name-' + item.name); }
+
+ $selectBoxes.children('.wPaint-menu-select-holder').hide();
+ }
+ },
+
+ /************************************
+ * events
+ ************************************/
+ //_imageOnload: function () {
+ // /* a blank helper function for post image load calls on canvas - can be extended by other plugins using the setImage called */
+ //},
+
+ _callShapeFunc: function (e) {
+
+ // TODO: this is where issues with mobile offsets are probably off
+ var canvasOffset = this.$canvas.offset(),
+ canvasEvent = e.canvasEvent.capitalize(),
+ func = '_draw' + this.options.mode.capitalize() + canvasEvent;
+
+ // update offsets here since we are detecting mouseup on $(document) not on the canvas
+ e.pageX = Math.floor(e.pageX - canvasOffset.left);
+ e.pageY = Math.floor(e.pageY - canvasOffset.top);
+
+ // call drawing func
+ if (this[func]) { this[func].apply(this, [e]); }
+
+ // run callback if set
+ if (this.options['draw' + canvasEvent]) { this.options['_draw' + canvasEvent].apply(this, [e]); }
+
+ // run options (user) callback if set
+ if (canvasEvent === 'Down' && this.options.onShapeDown) { this.options.onShapeDown.apply(this, [e]); }
+ else if (canvasEvent === 'Move' && this.options.onShapeMove) { this.options.onShapeMove.apply(this, [e]); }
+ else if (canvasEvent === 'Up' && this.options.onShapeUp) { this.options.onShapeUp.apply(this, [e]); }
+ },
+
+ _stopPropagation: function (e) {
+ e.stopPropagation();
+ },
+
+ /************************************
+ * shape helpers
+ ************************************/
+ _drawShapeDown: function (e) {
+ this.$canvasTemp
+ .css({left: e.PageX, top: e.PageY})
+ .attr('width', 0)
+ .attr('height', 0)
+ .show();
+
+ this.canvasTempLeftOriginal = e.pageX;
+ this.canvasTempTopOriginal = e.pageY;
+ },
+
+ _drawShapeMove: function (e, factor) {
+ var xo = this.canvasTempLeftOriginal,
+ yo = this.canvasTempTopOriginal;
+
+ // we may need these in other funcs, so we'll just pass them along with the event
+ factor = factor || 2;
+ e.left = (e.pageX < xo ? e.pageX : xo);
+ e.top = (e.pageY < yo ? e.pageY : yo);
+ e.width = Math.abs(e.pageX - xo);
+ e.height = Math.abs(e.pageY - yo);
+ e.x = this.options.lineWidth / 2 * factor;
+ e.y = this.options.lineWidth / 2 * factor;
+ e.w = e.width - this.options.lineWidth * factor;
+ e.h = e.height - this.options.lineWidth * factor;
+
+ $(this.canvasTemp)
+ .css({left: e.left, top: e.top})
+ .attr('width', e.width)
+ .attr('height', e.height);
+
+ // store these for later to use in our "up" call
+ this.canvasTempLeftNew = e.left;
+ this.canvasTempTopNew = e.top;
+
+ factor = factor || 2;
+
+ // TODO: set this globally in _drawShapeDown (for some reason colors are being reset due to canvas resize - is there way to permanently set it)
+ this.ctxTemp.fillStyle = this.options.fillStyle;
+ this.ctxTemp.strokeStyle = this.options.strokeStyle;
+ this.ctxTemp.lineWidth = this.options.lineWidth * factor;
+ },
+
+ _drawShapeUp: function () {
+ this.ctx.drawImage(this.canvasTemp, this.canvasTempLeftNew, this.canvasTempTopNew);
+ this.$canvasTemp.hide();
+ },
+
+ /****************************************
+ * dropper
+ ****************************************/
+ _drawDropperDown: function (e) {
+ var pos = {x: e.pageX, y: e.pageY},
+ pixel = this._getPixel(this.ctx, pos),
+ color = null;
+
+ // if we get no color try getting from the background
+ //if(pixel.r === 0 && pixel.g === 0 && pixel.b === 0 && pixel.a === 0) {
+ // imageData = this.ctxBg.getImageData(0, 0, this.width, this.height)
+ // pixel = this._getPixel(imageData, pos);
+ //}
+
+ color = 'rgba(' + [ pixel.r, pixel.g, pixel.b, pixel.a ].join(',') + ')';
+
+ // set color from dropper here
+ this.options[this.dropper] = color;
+ this.menus.active._getIcon(this.dropper).wColorPicker('color', color);
+ },
+
+ _drawDropperUp: function () {
+ this.setMode(this.previousMode);
+ },
+
+ // get pixel data represented as RGBa color from pixel array.
+ _getPixel: function (ctx, pos) {
+ var imageData = ctx.getImageData(0, 0, this.width, this.height),
+ pixelArray = imageData.data,
+ base = ((pos.y * imageData.width) + pos.x) * 4;
+
+ return {
+ r: pixelArray[base],
+ g: pixelArray[base + 1],
+ b: pixelArray[base + 2],
+ a: pixelArray[base + 3]
+ };
+ }
+ };
+
+ /************************************************************************
+ * Menu class
+ ************************************************************************/
+ function Menu(wPaint, name, options) {
+ this.wPaint = wPaint;
+ this.options = options;
+ this.name = name;
+ this.type = !wPaint.menus.primary ? 'primary' : 'secondary';
+ this.docked = true;
+ this.dockOffset = {left: 0, top: 0};
+
+ this.generate();
+ }
+
+ Menu.prototype = {
+ generate: function () {
+ this.$menu = $('<div class="wPaint-menu"></div>');
+ this.$menuHolder = $('<div class="wPaint-menu-holder wPaint-menu-name-' + this.name + '"></div>');
+
+ if (this.options.handle) { this.$menuHandle = this._createHandle(); }
+ else { this.$menu.addClass('wPaint-menu-nohandle'); }
+
+ if (this.type === 'primary') {
+
+ // store the primary menu in primary object - we will need this reference later
+ this.wPaint.menus.primary = this;
+
+ this.setOffsetLeft(this.options.offsetLeft);
+ this.setOffsetTop(this.options.offsetTop);
+ }
+ else if (this.type === 'secondary') {
+ this.$menu.hide();
+ }
+
+ // append menu items
+ this.$menu.append(this.$menuHolder.append(this.$menuHandle));
+ this.reset();
+
+ // append menu
+ this.wPaint.$el.append(this.$menu);
+
+ this.setAlignment(this.options.alignment);
+ },
+
+ // create / reset menu - will add new entries in the array
+ reset: function () {
+ var _this = this,
+ menu = $.fn.wPaint.menus[this.name],
+ key;
+
+ // self invoking function
+ function itemAppend(item) { _this._appendItem(item); }
+
+ for (key in menu.items) {
+
+ // only add unique (new) items (icons)
+ if (!this.$menuHolder.children('.wPaint-menu-icon-name-' + key).length) {
+
+ // add the item name, we will need this internally
+ menu.items[key].name = key;
+
+ // use default img if img not set
+ menu.items[key].img = _this.wPaint.options.path + (menu.items[key].img || menu.img);
+
+ // make self invoking to avoid overwrites
+ (itemAppend)(menu.items[key]);
+ }
+ }
+ },
+
+ _appendItem: function (item) {
+ var $item = this['_createIcon' + item.icon.capitalize()](item);
+
+ if (item.after) {
+ this.$menuHolder.children('.wPaint-menu-icon-name-' + item.after).after($item);
+ }
+ else {
+ this.$menuHolder.append($item);
+ }
+ },
+
+ /************************************
+ * setters
+ ************************************/
+ setOffsetLeft: function (left) {
+ this.$menu.css({left: left});
+ },
+
+ setOffsetTop: function (top) {
+ this.$menu.css({top: top});
+ },
+
+ setAlignment: function (alignment) {
+ var tempLeft = this.$menu.css('left');
+
+ this.$menu.attr('class', this.$menu.attr('class').replace(/wPaint-menu-alignment-.+\s|wPaint-menu-alignment-.+$/, ''));
+ this.$menu.addClass('wPaint-menu-alignment-' + alignment);
+
+ this.$menu.width('auto').css('left', -10000);
+ this.$menu.width(this.$menu.width()).css('left', tempLeft);
+
+ // set proper offsets based on alignment
+ if (this.type === 'secondary') {
+ if (this.options.alignment === 'horizontal') {
+ this.dockOffset.top = this.wPaint.menus.primary.$menu.outerHeight(true);
+ }
+ else {
+ this.dockOffset.left = this.wPaint.menus.primary.$menu.outerWidth(true);
+ }
+ }
+ },
+
+ /************************************
+ * handle
+ ************************************/
+ _createHandle: function () {
+ var _this = this,
+ $handle = $('<div class="wPaint-menu-handle"></div>');
+
+ // draggable functions
+ function draggableStart() {
+ _this.docked = false;
+ _this._setDrag();
+ }
+
+ function draggableStop() {
+ $.each(_this.$menu.data('ui-draggable').snapElements, function (i, el) {
+ var offset = _this.$menu.offset(),
+ offsetPrimary = _this.wPaint.menus.primary.$menu.offset();
+
+ _this.dockOffset.left = offset.left - offsetPrimary.left;
+ _this.dockOffset.top = offset.top - offsetPrimary.top;
+ _this.docked = el.snapping;
+ });
+
+ _this._setDrag();
+ }
+
+ function draggableDrag() {
+ _this._setIndex();
+ }
+
+ // the drag/snap events for menus are tricky
+ // init handle for ALL menus, primary menu will drag a secondary menu with it, but that is un/binded in the toggle function
+ this.$menu.draggable({handle: $handle});
+
+ // if it's a secondary menu we want to check for snapping
+ // on drag we set docked to false, on snap we set it back to true
+ if (this.type === 'secondary') {
+ this.$menu.draggable('option', 'snap', this.wPaint.menus.primary.$menu);
+ this.$menu.draggable('option', 'start', draggableStart);
+ this.$menu.draggable('option', 'stop', draggableStop);
+ this.$menu.draggable('option', 'drag', draggableDrag);
+ }
+
+ $handle.bindMobileEvents();
+
+ return $handle;
+ },
+
+ /************************************
+ * generic icon
+ ************************************/
+ _createIconBase: function (item) {
+ var _this = this,
+ $icon = $('<div class="wPaint-menu-icon wPaint-menu-icon-name-' + item.name + '"></div>'),
+ $iconImg = $('<div class="wPaint-menu-icon-img"></div>'),
+ width = $iconImg.realWidth(null, null, this.wPaint.$el);
+
+ function mouseenter(e) {
+ var $el = $(e.currentTarget);
+
+ $el.siblings('.hover').removeClass('hover');
+ if (!$el.hasClass('disabled')) { $el.addClass('hover'); }
+ }
+
+ function mouseleave(e) {
+ $(e.currentTarget).removeClass('hover');
+ }
+
+ function click() {
+ _this.wPaint.menus.active = _this;
+ }
+
+ $icon
+ .attr('title', item.title)
+ .on('mousedown', $.proxy(this.wPaint._closeSelectBoxes, this.wPaint, item))
+ .on('mouseenter', mouseenter)
+ .on('mouseleave', mouseleave)
+ .on('click', click);
+
+ // can have index:0 so be careful here
+ if ($.isNumeric(item.index)) {
+ $iconImg
+ .css({
+ backgroundImage: 'url(' + item.img + ')',
+ backgroundPosition: (-width * item.index) + 'px 0px'
+ });
+ }
+
+ return $icon.append($iconImg);
+ },
+
+ /************************************
+ * icon group
+ ************************************/
+ _createIconGroup: function (item) {
+ var _this = this,
+ css = {backgroundImage: 'url(' + item.img + ')'},
+ $icon = this.$menuHolder.children('.wPaint-menu-icon-group-' + item.group),
+ iconExists = $icon.length,
+ $selectHolder = null,
+ $option = null,
+ $item = null,
+ width = 0;
+
+ // local functions
+ function setIconClick() {
+
+ // only trigger if menu is not visible otherwise it will fire twice
+ // from the mousedown to open the menu which we want just to display the menu
+ // not fire the button callback
+ if (!$icon.children('.wPaint-menu-select-holder').is(':visible')) {
+ item.callback.apply(_this.wPaint, []);
+ }
+ }
+
+ function selectHolderClick() {
+ $icon.addClass('active').siblings('.active').removeClass('active');
+ }
+
+ function optionClick() {
+
+ // rebind the main icon when we select an option
+ $icon
+ .attr('title', item.title)
+ .off('click.setIcon')
+ .on('click.setIcon', setIconClick);
+
+ // run the callback right away when we select an option
+ $icon.children('.wPaint-menu-icon-img').css(css);
+ item.callback.apply(_this.wPaint, []);
+ }
+
+ // crate icon if it doesn't exist yet
+ if (!iconExists) {
+ $icon = this._createIconBase(item)
+ .addClass('wPaint-menu-icon-group wPaint-menu-icon-group-' + item.group)
+ .on('click.setIcon', setIconClick)
+ .on('mousedown', $.proxy(this._iconClick, this));
+ }
+
+ // get the proper width here now that we have the icon
+ // this is for the select box group not the main icon
+ width = $icon.children('.wPaint-menu-icon-img').realWidth(null, null, this.wPaint.$el);
+ css.backgroundPosition = (-width * item.index) + 'px center';
+
+ // create selectHolder if it doesn't exist
+ $selectHolder = $icon.children('.wPaint-menu-select-holder');
+ if (!$selectHolder.length) {
+ $selectHolder = this._createSelectBox($icon);
+ $selectHolder.children().on('click', selectHolderClick);
+ }
+
+ $item = $('<div class="wPaint-menu-icon-select-img"></div>')
+ .attr('title', item.title)
+ .css(css);
+
+ $option = this._createSelectOption($selectHolder, $item)
+ .addClass('wPaint-menu-icon-name-' + item.name)
+ .on('click', optionClick);
+
+ // move select option into place if after is set
+ if (item.after) {
+ $selectHolder.children('.wPaint-menu-select').children('.wPaint-menu-icon-name-' + item.after).after($option);
+ }
+
+ // we only want to return an icon to append on the first run of a group
+ if (!iconExists) { return $icon; }
+ },
+
+ /************************************
+ * icon generic
+ ************************************/
+ _createIconGeneric: function (item) {
+
+ // just a go between for the iconGeneric type
+ return this._createIconActivate(item);
+ },
+
+ /************************************
+ * icon
+ ************************************/
+ _createIconActivate: function (item) {
+
+ // since we are piggy backing icon with the item.group
+ // we'll just do a redirect and keep the code separate for group icons
+ if (item.group) { return this._createIconGroup(item); }
+
+ var _this = this,
+ $icon = this._createIconBase(item);
+
+ function iconClick(e) {
+ if (item.icon !== 'generic') { _this._iconClick(e); }
+ item.callback.apply(_this.wPaint, [e]);
+ }
+
+ $icon.on('click', iconClick);
+
+ return $icon;
+ },
+
+ _isIconDisabled: function (name) {
+ return this.$menuHolder.children('.wPaint-menu-icon-name-' + name).hasClass('disabled');
+ },
+
+ _setIconDisabled: function (name, disabled) {
+ var $icon = this.$menuHolder.children('.wPaint-menu-icon-name-' + name);
+
+ if (disabled) {
+ $icon.addClass('disabled').removeClass('hover');
+ }
+ else {
+ $icon.removeClass('disabled');
+ }
+ },
+
+ _getIcon: function (name) {
+ return this.$menuHolder.children('.wPaint-menu-icon-name-' + name);
+ },
+
+ _iconClick: function (e) {
+ var $el = $(e.currentTarget),
+ menus = this.wPaint.menus.all;
+
+ // make sure to loop using parent object - don't use .wPaint-menu-secondary otherwise we would hide menu for all canvases
+ for (var menu in menus) {
+ if (menus[menu] && menus[menu].type === 'secondary') { menus[menu].$menu.hide(); }
+ }
+
+ $el.siblings('.active').removeClass('active');
+ if (!$el.hasClass('disabled')) { $el.addClass('active'); }
+ },
+
+ /************************************
+ * iconToggle
+ ************************************/
+ _createIconToggle: function (item) {
+ var _this = this,
+ $icon = this._createIconBase(item);
+
+ function iconClick() {
+ $icon.toggleClass('active');
+ item.callback.apply(_this.wPaint, [$icon.hasClass('active')]);
+ }
+
+ $icon.on('click', iconClick);
+
+ return $icon;
+ },
+
+ /************************************
+ * select
+ ************************************/
+ _createIconSelect: function (item) {
+ var _this = this,
+ $icon = this._createIconBase(item),
+ $selectHolder = this._createSelectBox($icon),
+ i, ii, $option;
+
+ function optionClick(e) {
+ $icon.children('.wPaint-menu-icon-img').html($(e.currentTarget).html());
+ item.callback.apply(_this.wPaint, [$(e.currentTarget).html()]);
+ }
+
+ // add values for select
+ for (i = 0, ii = item.range.length; i < ii; i++) {
+ $option = this._createSelectOption($selectHolder, item.range[i]);
+ $option.on('click', optionClick);
+ if (item.useRange) { $option.css(item.name, item.range[i]); }
+ }
+
+ return $icon;
+ },
+
+ _createSelectBox: function ($icon) {
+ var $selectHolder = $('<div class="wPaint-menu-select-holder"></div>'),
+ $select = $('<div class="wPaint-menu-select"></div>'),
+ timer = null;
+
+ function clickSelectHolder(e) {
+ e.stopPropagation();
+ $selectHolder.hide();
+ }
+
+ function iconMousedown() {
+ timer = setTimeout(function () { $selectHolder.toggle(); }, 200);
+ }
+
+ function iconMouseup() {
+ clearTimeout(timer);
+ }
+
+ function iconClick() {
+ $selectHolder.toggle();
+ }
+
+ $selectHolder
+ .on('mousedown mouseup', this.wPaint._stopPropagation)
+ .on('click', clickSelectHolder)
+ .hide();
+
+ // of hozizontal we'll pop below the icon
+ if (this.options.alignment === 'horizontal') {
+ $selectHolder.css({left: 0, top: $icon.children('.wPaint-menu-icon-img').realHeight('outer', true, this.wPaint.$el)});
+ }
+ // vertical we'll pop to the right
+ else {
+ $selectHolder.css({left: $icon.children('.wPaint-menu-icon-img').realWidth('outer', true, this.wPaint.$el), top: 0});
+ }
+
+ $icon
+ .addClass('wPaint-menu-icon-select')
+ .append('<div class="wPaint-menu-icon-group-arrow"></div>')
+ .append($selectHolder.append($select));
+
+ // for groups we want to add a delay before the selectBox pops up
+ if ($icon.hasClass('wPaint-menu-icon-group')) {
+ $icon
+ .on('mousedown', iconMousedown)
+ .on('mouseup', iconMouseup);
+ }
+ else { $icon.on('click', iconClick); }
+
+ return $selectHolder;
+ },
+
+ _createSelectOption: function ($selectHolder, value) {
+ var $select = $selectHolder.children('.wPaint-menu-select'),
+ $option = $('<div class="wPaint-menu-select-option"></div>').append(value);
+
+ // set class for first item to remove any undesired styles like borders
+ if (!$select.children().length) { $option.addClass('first'); }
+
+ $select.append($option);
+
+ return $option;
+ },
+
+ _setSelectValue: function (icon, value) {
+ this._getIcon(icon).children('.wPaint-menu-icon-img').html(value);
+ },
+
+ /************************************
+ * color picker
+ ************************************/
+ _createIconColorPicker: function (item) {
+ var _this = this,
+ $icon = this._createIconBase(item);
+
+ function iconClick() {
+
+ // if we happen to click on this while in dropper mode just revert to previous
+ if (_this.wPaint.options.mode === 'dropper') { _this.wPaint.setMode(_this.wPaint.previousMode); }
+ }
+
+ function iconOnSelect(color) {
+ item.callback.apply(_this.wPaint, [color]);
+ }
+
+ function iconOnDropper() {
+ $icon.trigger('click');
+ _this.wPaint.dropper = item.name;
+ _this.wPaint.setMode('dropper');
+ }
+
+ $icon
+ .on('click', iconClick)
+ .addClass('wPaint-menu-colorpicker')
+ .wColorPicker({
+ mode: 'click',
+ generateButton: false,
+ dropperButton: true,
+ onSelect: iconOnSelect,
+ onDropper: iconOnDropper
+ });
+
+ return $icon;
+ },
+
+ _setColorPickerValue: function (icon, value) {
+ this._getIcon(icon).children('.wPaint-menu-icon-img').css('backgroundColor', value);
+ },
+
+ /************************************
+ * menu toggle
+ ************************************/
+ _createIconMenu: function (item) {
+ var _this = this,
+ $icon = this._createIconActivate(item);
+
+ function iconClick() {
+ _this.wPaint.setCursor(item.name);
+
+ // the items name here will be the menu name
+ var menu = _this.wPaint.menus.all[item.name];
+ menu.$menu.toggle();
+ if (_this.handle) {
+ menu._setDrag();
+ } else {
+ menu._setPosition();
+ }
+ }
+
+ $icon.on('click', iconClick);
+
+ return $icon;
+ },
+
+ // here we specify which menu will be dragged
+ _setDrag: function () {
+ var $menu = this.$menu,
+ drag = null, stop = null;
+
+ if ($menu.is(':visible')) {
+ if (this.docked) {
+
+ // make sure we are setting proper menu object here
+ drag = stop = $.proxy(this._setPosition, this);
+ this._setPosition();
+ }
+
+ // register drag/stop events
+ this.wPaint.menus.primary.$menu.draggable('option', 'drag', drag);
+ this.wPaint.menus.primary.$menu.draggable('option', 'stop', stop);
+ }
+ },
+
+ _setPosition: function () {
+ var offset = this.wPaint.menus.primary.$menu.position();
+
+ this.$menu.css({
+ left: offset.left + this.dockOffset.left,
+ top: offset.top + this.dockOffset.top
+ });
+ },
+
+ _setIndex: function () {
+ var primaryOffset = this.wPaint.menus.primary.$menu.offset(),
+ secondaryOffset = this.$menu.offset();
+
+ if (
+ secondaryOffset.top < primaryOffset.top ||
+ secondaryOffset.left < primaryOffset.left
+ ) {
+ this.$menu.addClass('wPaint-menu-behind');
+ }
+ else {
+ this.$menu.removeClass('wPaint-menu-behind');
+ }
+ }
+ };
+
+ /************************************************************************
+ * wPaint
+ ************************************************************************/
+ $.support.canvas = (document.createElement('canvas')).getContext;
+
+ $.fn.wPaint = function (options, value) {
+
+ function create() {
+ if (!$.support.canvas) {
+ $(this).html('Browser does not support HTML5 canvas, please upgrade to a more modern browser.');
+ return false;
+ }
+
+ return $.proxy(get, this)();
+ }
+
+ function get() {
+ var wPaint = $.data(this, 'wPaint');
+
+ if (!wPaint) {
+ wPaint = new Paint(this, $.extend(true, {}, options));
+ $.data(this, 'wPaint', wPaint);
+ }
+
+ return wPaint;
+ }
+
+ function runOpts() {
+ var wPaint = $.data(this, 'wPaint');
+
+ if (wPaint) {
+ if (wPaint[options]) { wPaint[options].apply(wPaint, [value]); }
+ else if (value !== undefined) {
+ if (wPaint[func]) { wPaint[func].apply(wPaint, [value]); }
+ if (wPaint.options[options]) { wPaint.options[options] = value; }
+ }
+ else {
+ if (wPaint[func]) { values.push(wPaint[func].apply(wPaint, [value])); }
+ else if (wPaint.options[options]) { values.push(wPaint.options[options]); }
+ else { values.push(undefined); }
+ }
+ }
+ }
+
+ if (typeof options === 'string') {
+ var values = [],
+ func = (value ? 'set' : 'get') + options.charAt(0).toUpperCase() + options.substring(1);
+
+ this.each(runOpts);
+
+ if (values.length) { return values.length === 1 ? values[0] : values; }
+
+ return this;
+ }
+
+ options = $.extend({}, $.fn.wPaint.defaults, options);
+ options.lineWidth = parseInt(options.lineWidth, 10);
+ options.fontSize = parseInt(options.fontSize, 10);
+
+ return this.each(create);
+ };
+
+ /************************************************************************
+ * extend
+ ************************************************************************/
+ $.fn.wPaint.extend = function (funcs, protoType) {
+ var key;
+
+ function elEach(func) {
+ if (protoType[func]) {
+ var tmpFunc = Paint.prototype[func],
+ newFunc = funcs[func];
+
+ protoType[func] = function () {
+ tmpFunc.apply(this, arguments);
+ newFunc.apply(this, arguments);
+ };
+ }
+ else {
+ protoType[func] = funcs[func];
+ }
+ }
+
+ protoType = protoType === 'menu' ? Menu.prototype : Paint.prototype;
+
+ for (key in funcs) { (elEach)(key); }
+ };
+
+ /************************************************************************
+ * Init holders
+ ************************************************************************/
+ $.fn.wPaint.menus = {};
+
+ $.fn.wPaint.cursors = {};
+
+ $.fn.wPaint.defaults = {
+ path: '/', // set absolute path for images and cursors
+ theme: 'standard classic', // set theme
+ autoScaleImage: true, // auto scale images to size of canvas (fg and bg)
+ autoCenterImage: true, // auto center images (fg and bg, default is left/top corner)
+ menuHandle: true, // setting to false will means menus cannot be dragged around
+ menuOrientation: 'horizontal', // menu alignment (horizontal,vertical)
+ menuOffsetLeft: 5, // left offset of primary menu
+ menuOffsetTop: 5, // top offset of primary menu
+ bg: null, // set bg on init
+ image: null, // set image on init
+ imageStretch: false, // stretch smaller images to full canvans dimensions
+ onShapeDown: null, // callback for draw down event
+ onShapeMove: null, // callback for draw move event
+ onShapeUp: null // callback for draw up event
+ };
+})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/src/wPaint.utils.js b/static/js/wpaint/src/wPaint.utils.js
new file mode 100644
index 0000000..7f1346a
--- /dev/null
+++ b/static/js/wpaint/src/wPaint.utils.js
@@ -0,0 +1,70 @@
+(function () {
+ if (!String.prototype.capitalize) {
+ String.prototype.capitalize = function () {
+ return this.slice(0, 1).toUpperCase() + this.slice(1);
+ };
+ }
+})();
+
+(function ($) {
+ $.fn.realWidth = function (type, margin, $el) {
+ var width = null, $div = null, method = null;
+
+ type = type === 'inner' || type === 'outer' ? type : '';
+ method = type === '' ? 'width' : type + 'Width';
+ margin = margin === true ? true : false;
+ $div = $(this).clone().css({position: 'absolute', left: -10000}).appendTo($el || 'body');
+ width = margin ? $div[method](margin) : $div[method]();
+
+ $div.remove();
+
+ return width;
+ };
+
+ $.fn.realHeight = function (type, margin, $el) {
+ var height = null, $div = null, method = null;
+
+ type = type === 'inner' || type === 'outer' ? type : '';
+ method = type === '' ? 'height' : type + 'Height';
+ margin = margin === true ? true : false;
+ $div = $(this).clone().css({position: 'absolute', left: -10000}).appendTo($el || 'body');
+ height = margin ? $div[method](margin) : $div[method]();
+
+ $div.remove();
+
+ return height;
+ };
+
+ $.fn.bindMobileEvents = function () {
+ $(this).on('touchstart touchmove touchend touchcancel', function () {
+ var touches = (event.changedTouches || event.originalEvent.targetTouches),
+ first = touches[0],
+ type = '';
+
+ switch (event.type) {
+ case 'touchstart':
+ type = 'mousedown';
+ break;
+ case 'touchmove':
+ type = 'mousemove';
+ event.preventDefault();
+ break;
+ case 'touchend':
+ type = 'mouseup';
+ break;
+ default:
+ return;
+ }
+
+ var simulatedEvent = document.createEvent('MouseEvent');
+
+ simulatedEvent.initMouseEvent(
+ type, true, true, window, 1,
+ first.screenX, first.screenY, first.clientX, first.clientY,
+ false, false, false, false, 0/*left*/, null
+ );
+
+ first.target.dispatchEvent(simulatedEvent);
+ });
+ };
+})(jQuery); \ No newline at end of file
diff --git a/static/js/wpaint/test/dev.html b/static/js/wpaint/test/dev.html
new file mode 100644
index 0000000..b9cd1bf
--- /dev/null
+++ b/static/js/wpaint/test/dev.html
@@ -0,0 +1,123 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width" />
+
+ <title>Websanova :: wPaint</title>
+
+ <link rel="icon" type="image/vnd.microsoft.icon" href="./demo/img/favicon.ico" />
+ <script type="text/javascript" src="../lib/jquery.1.10.2.min.js"></script>
+</head>
+<body>
+
+ <!-- jQuery UI -->
+ <script type="text/javascript" src="../lib/jquery.ui.core.1.10.3.min.js"></script>
+ <script type="text/javascript" src="../lib/jquery.ui.widget.1.10.3.min.js"></script>
+ <script type="text/javascript" src="../lib/jquery.ui.mouse.1.10.3.min.js"></script>
+ <script type="text/javascript" src="../lib/jquery.ui.draggable.1.10.3.min.js"></script>
+
+ <!-- wColorPicker -->
+ <link rel="Stylesheet" type="text/css" href="../lib/wColorPicker.min.css" />
+ <script type="text/javascript" src="../lib/wColorPicker.min.js"></script>
+
+ <!-- wPaint -->
+ <link rel="Stylesheet" type="text/css" href="../src/wPaint.css" />
+ <script type="text/javascript" src="../src/wPaint.utils.js"></script>
+ <script type="text/javascript" src="../src/wPaint.js"></script>
+
+ <!-- wPaint main -->
+ <script type="text/javascript" src="../plugins/main/src/fillArea.min.js"></script>
+ <script type="text/javascript" src="../plugins/main/src/wPaint.menu.main.js"></script>
+
+ <!-- wPaint text -->
+ <script type="text/javascript" src="../plugins/text/src/wPaint.menu.text.js"></script>
+
+ <!-- wPaint shapes -->
+ <script type="text/javascript" src="../plugins/shapes/src/shapes.min.js"></script>
+ <script type="text/javascript" src="../plugins/shapes/src/wPaint.menu.main.shapes.js"></script>
+
+ <!-- wPaint file -->
+ <script type="text/javascript" src="../plugins/file/src/wPaint.menu.main.file.js"></script>
+
+ <div id="wPaint-demo1" style="position:relative; width:500px; height:200px; background-color:#7a7a7a; margin:70px auto 20px auto;"></div>
+
+ <center style="margin-bottom: 50px;">
+ <input type="button" value="toggle menu" onclick="console.log($('#wPaint-demo1').wPaint('menuOrientation')); $('#wPaint-demo1').wPaint('menuOrientation', $('#wPaint-demo1').wPaint('menuOrientation') === 'vertical' ? 'horizontal' : 'vertical');"/>
+ </center>
+
+ <center id="wPaint-img"></center>
+
+ <script type="text/javascript">
+ var images = [
+ '/test/uploads/wPaint.png',
+ ];
+
+ function saveImg(image) {
+ var _this = this;
+
+ $.ajax({
+ type: 'POST',
+ url: '/test/upload.php',
+ data: {image: image},
+ success: function (resp) {
+
+ // internal function for displaying status messages in the canvas
+ _this._displayStatus('Image saved successfully');
+
+ // doesn't have to be json, can be anything
+ // returned from server after upload as long
+ // as it contains the path to the image url
+ // or a base64 encoded png, either will work
+ resp = $.parseJSON(resp);
+
+ // update images array / object or whatever
+ // is being used to keep track of the images
+ // can store path or base64 here (but path is better since it's much smaller)
+ images.push(resp.img);
+
+ // do something with the image
+ $('#wPaint-img').append($('<img/>').attr('src', image));
+ }
+ });
+ }
+
+ function loadImgBg () {
+
+ // internal function for displaying background images modal
+ // where images is an array of images (base64 or url path)
+ // NOTE: that if you can't see the bg image changing it's probably
+ // becasue the foregroud image is not transparent.
+ this._showFileModal('bg', images);
+ }
+
+ function loadImgFg () {
+
+ // internal function for displaying foreground images modal
+ // where images is an array of images (base64 or url path)
+ this._showFileModal('fg', images);
+ }
+
+ function createCallback(cbName) {
+ return function() {
+ if (console) {
+ console.log(cbName, arguments);
+ }
+ }
+ }
+
+ // init wPaint
+ $('#wPaint-demo1').wPaint({
+ menuOffsetLeft: -35,
+ menuOffsetTop: -50,
+ saveImg: saveImg,
+ loadImgBg: loadImgBg,
+ loadImgFg: loadImgFg,
+ onShapeDown: createCallback('onShapeDown'),
+ onShapeUp: createCallback('onShapeUp'),
+ onShapeMove: createCallback('onShapeDMove')
+ });
+ </script>
+
+</body>
+</html> \ No newline at end of file
diff --git a/static/js/wpaint/test/fullscreen.html b/static/js/wpaint/test/fullscreen.html
new file mode 100644
index 0000000..91b3e15
--- /dev/null
+++ b/static/js/wpaint/test/fullscreen.html
@@ -0,0 +1,79 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width" />
+
+ <title>Websanova :: Paint</title>
+
+ <script type="text/javascript" src="../lib/jquery.1.10.2.min.js"></script>
+</head>
+<body>
+ <!-- jQuery UI -->
+ <script type="text/javascript" src="../lib/jquery.ui.core.1.10.3.min.js"></script>
+ <script type="text/javascript" src="../lib/jquery.ui.widget.1.10.3.min.js"></script>
+ <script type="text/javascript" src="../lib/jquery.ui.mouse.1.10.3.min.js"></script>
+ <script type="text/javascript" src="../lib/jquery.ui.draggable.1.10.3.min.js"></script>
+
+ <!-- wColorPicker -->
+ <link rel="Stylesheet" type="text/css" href="../lib/wColorPicker.min.css" />
+ <script type="text/javascript" src="../lib/wColorPicker.min.js"></script>
+
+ <!-- wPaint -->
+ <link rel="Stylesheet" type="text/css" href="../src/wPaint.css" />
+ <script type="text/javascript" src="../src/wPaint.utils.js"></script>
+ <script type="text/javascript" src="../src/wPaint.js"></script>
+
+ <!-- wPaint main -->
+ <script type="text/javascript" src="../plugins/main/src/fillArea.min.js"></script>
+ <script type="text/javascript" src="../plugins/main/src/wPaint.menu.main.js"></script>
+
+ <!-- wPaint text -->
+ <script type="text/javascript" src="../plugins/text/src/wPaint.menu.text.js"></script>
+
+ <!-- wPaint shapes -->
+ <script type="text/javascript" src="../plugins/shapes/src/shapes.min.js"></script>
+ <script type="text/javascript" src="../plugins/shapes/src/wPaint.menu.main.shapes.js"></script>
+
+ <!-- wPaint file -->
+ <script type="text/javascript" src="../plugins/file/src/wPaint.menu.main.file.js"></script>
+
+ <div id="wPaint" style="position:relative; width:200px; height:200px; background:#CACACA;"></div>
+
+ <style>
+ body, html {
+ margin: 0px;
+ overflow: hidden;
+ }
+ </style>
+
+ <script type="text/javascript">
+
+ // update elements dimensions
+ // call wPaint('resize')
+ $(window).resize(function () {
+ $('#wPaint').css({
+ width: $(window).width(),
+ height: $(window).height()
+ })
+ .wPaint('resize');
+ })
+
+ // init size based on browser dimensions
+ $(window).resize();
+
+ // set test image
+ // get from tapping enter below
+ $('#wPaint').wPaint({
+ image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAYAAAErCAYAAABNUIGWAAARs0lEQVR4nO3dzY4dV7UH8PUkvMh9CXgC9yATBr5vgMSAGSNGSJdRELN7lUQRwys5EoMgpCsEkWywxFWIMCDHOI4SN273x2LgOnT1PlWnz8euj3Pq95OOlNh99l51Plpe/9q1KwIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmKnMuMmMm6nrAAAAAEbWhALZPIQDAAAAsCStUCAzIyuPfZkZ1/c8LmvOCQAAAOygdjCQGReZcVWsRLjvIRwAAACAKRwSDGTGeSsE2CUIKB83mXE+1DECAAAAPXYJBjLj6x2DgJt7LiMox1iNawUBAAAAjKFpyK9bTXn56Gvi7wsD7m3umz0IXF7ATppw6mrqOgAAAE5C08QfcgnATdOoXew5/2XPCgR3SGBN81lbfUaEAwAAAIfaIxhYBQHV9wTId3sWtAMCqwa4I91eEwAAoK4tLiX493X/mfF0hHouNX70EQwAAABUVq4ImLqeiLXmz6oB/k0wAAAAUNlMgwGrBugkGAAAAKhsjsFAhFUDdBMMAAAAVDbjYOBKA0hJMAAAAFDZjIOBr4raPp26JqYnGAAAgIVodsm/nrqOJZhrMBDhcgLWCQYAAGABmlDAP/xHMvNgwCaE3CEYAACABSiCgcyMq6lrOmVzDgYi1hpBq0gWTjAAAAALUf7jPzPOp67pVB1BMHBZ1OizsGCCAQAAWIjM+KIjHPhi6rpO0dyDgQjNILd8FgAAYEEy41wT8E5mPMiMBwONfQzBwHlRp40IF8rvBAAAWJjiXvaLvMY8M85ax382wPhH8foWe0/Mtk6GJRgAAIAFWnojkBkfto7/wwHGbwcDX9YevxbBABF+HwAAwGIteWf6zHjUOvZHA4wvGOBoCAYAAGChiqZwUc1AZjxuHfvjAcY/lmDgaqmfAW4JBgAAYMGWumogM563jvv5AOO3g4H/rD1+LZnxZVHr/05dE+MTDAAAwIItddVAZrxsHffLAcaf9R0J2oqm0J0JFkgwAAAAC7fEVQOCgVv2GUAwAAAAC7fEpiAzvm0d87eVx/5IMMAxWeLvAAAAoGWJTUFmnLeO+bzy2F8KBjgmS/wdAAAAtCyxKciMi9YxX1QeWzDAUVni7wAAAKBliRsQZsbb1jG/rTy2YICjIhgAAICFK86eL6IpyIzLoXbib4cCggGOgWAAAAA4ql30a8iMq9YxX1UeWzDAUSm+D4IBAABYouKMYdVr7udIMHBLMEBmvBAMAADAwhXBwMk3h4KBW4IBItZ+B7yYuh4AAGBkS9uAcMhmWDDAMSqCgaphGQAAcAQy4+uiof1i6pqGJBi4JRggwj4DAABArJ0xrLpT/9wIBm4JBoiwzwAAABDLOmMoGLglGGDFPgMAALBwS7qcoGiA3lQeWzDAUbLPAAAAsIjLCTLjs/bKiMx4WHn8tWAgMx5kxoOa89QiGDhdzSqgm+Zx7/d56M9CZvxXZnww1+8CAAAQa8HASV5OMELzk8XjrPXfv86M/6g95yEEA6epuDRoq+90Zryu/f3PjP/OjL9kxnn5vagxPgAAUNlYwUBmXDYN6airEjLjYXGMnw0wx6ZgYPW4yIxHtefexxJWiSxRTzCwWiVz3fO4KR7l31+1HpeZ8bb1uGia//Pm/2965hcMAADAnI0RDBRnqEdtRpuGZejj67qU4FcbmrTHQ9SxZa2XYwRBTCPvXkqwqUkf8/FCKAAAADM2ZDDQnEnsalBGa0hzhM3VuoKB5s8/zIy/zikgyAWsFsh3KzYWf037hOHATb5bTfA8Mz6Z+nUAAADuMUQwkLeXDWxqHkZpSovjezrQHJ3BQOvvv5MZn/SFJJnxVWb8fIjaWjVcDhkCzUXevYzjbOp6urS+H6vHYN+F1vu+7+UE215K8I/M+J+hjgMAABhQVt6IbkMgsGoyRmtMM+PpGPPt0nBnxpOegGAVElxnxj8q1vayZ75TXi0wy2CgI5wpvx9/mqiudk2vp6gBAACYUHPWr0rznOu7kK+a3fPm778q/u7TOkfRW88oQcQ+Z+LvCQhWr9vHB9bVG9IcMu7cNeHA2dR1tOXdvR3uW4Y/9gad7lIBAABLVjkYuLmvwSl+ZtAmpGh4BtlfoJln7yX6mfEsb5dzV7nkYsOZ6dHvCrF0eXcpf9fqkN4VBCPWOOpKHgAAYIbaDcmez+9qRM83/OwoDVBR06uR5tm7scqMn+fduyi0m8i3mfGLDc9dXbfet4/By33rYj89qwTWArMNQc5gn9li/k8P/R0AAAAcuX2bguy/68DGZj/Xl7gPchZ7rGanVjDQGu/jDWeSuzaR2/SzVghMpOd96X0/MuP92p+lPWu9GGteAABgJvZpCjqa+50a0eL51RugzHg1VoM1VDOXGd9saPpndZ06d3UENlu9J8XndrRLCtI+AwAAsGy7BgPZvUR652aimLdaI5sZPyrGHnovg0HP8mbGmy0CgtVKAoHAiFarNjr+rHx/tt7jouP5g18GkhX3GgEAAI7QrmcLO86Edu4nsMU4l7WbkZ6z7IM2y0MHA6153mtCgvJSAmHABPq+Nx3fj503vhzrM1XM2f7ODHrHEAAAYGZ2CQZy/ZaEjw+cu9qqgZ4ztYMvi56iiWN6fe97jc9DZrwcM9xq5mzXPdhdPAAAgBnaJhjI7p3Ta2y0V+Xa5ly/vOEmM745tL4t515UMJC3189v85jN9eqrmiqPV17KUX5HDvlMD7oPxz3zzeZ9AwAARpD33Me850x8lbOYtZqfcpzM+NGhte0w92KCgY7Gd5vH5E3mEO9RRzCwtu/DgeP/rhjvJzXq3jDfaBt2AgAAM5MZXxcNyBetvzvo7gNbzF2e6d+riSwas9c1attz7pNtqPYMBeYSDNypqcJ4ZRC1tnqgUt2DbNDZM9efl/A5BgAAenQ1IF1Ne2Y8GWDuMnzYuQGq2fTtMffJLsHOu5cNdAVEmx6rn/m/GRzHWv0Vx1sLBirWXX2Dznvmm+x7BAAATKyruS2anTFv+bfTXJnxesozncVr92rs+YfSEdhsdUa8I1CquspkX101HTDWKMFAx1xj3mHjz0POBQAAzEx5ZjLXLy/448Dz733Wfeoz9sXr9Pux5x9K3yqBLZ7XFyisPltXmfFojGPoqK3KqoGOYGCwSyfGXDVQHMvJhFwAAMCWNjQ7Yyxh3qv5yfXbJ45+VvoUg4GOZnfr6+Zz/fr7TSHBqO9XZrxf1LDXfhQbjmuQ78pYqwamDtkAAICJbTjTO0rzljteTpAZPxk7wOipo/1a/XiKGmrq+Bzs9Lp2BEw/zu7bXbZ/5ulQx9NR38GrBjYcy3ntepv5Rlk1IBgAAICF6wkGRmu2c8c7FHQ0oIPezm1DHQcvTZ+TQ8OWTc+/JyC4zoyH9Y6kt77Xxbzv7zHGaKsFWnMOvmpAMAAAAAvX0ZiPvjS/I5xYa04y46cdzeUgZ2q3ceLBwM7N4TbBQmb8oC+Iav78s8OPZGONh6yIuJoiQBtj1YBgAAAAWDUf181jkl3kN4UDmfHPjlBgsgYmM753SsFA8drv1XzusuIgM55uWEFwkxlv9juSnWrc6X3rCzSGqLNj7kFXDQgGAACA2egKB3oaskmbl8z4/YkFAwfv2bDPGJnxdkNAUP09zoxvDggG9rpbQw1DrxoQDAAAALPSEwS0zyb/cwY1CgY2j3G143M/a973wVeFFON/s8PzJgsGOuavfWtEwQAAADAvfcu2M+OnU9cWEZEZf5miORzKocFAjWChGedhx3u/U8iwxRx7NfYzCAbKvUA+rzi2YAAAAJifOTcreXcjuqqN6xQOaewz42+1z2Z3hAOPDh2zNfZe+wxMHQx01FBt7jl/1wAAgIVrzpJOshniJsXZ29nVt6uORnzfM+k1m9Whxt1rn4GZBAOfF/NX+exlxt9PaQUMAADA4DLjTauRGmQH/bF1NL73njnOjIviORcV63k0RBPcjL3zPgM9wcDoZ9ezwh0kOsb8QDAAAACwg1MMBiLWz9I3j97md6iz+q3xr4pG/LeVxt35rH9PMDD6ZST57laPQ6ykOJnNNAEAAAZ3qsFARP+S+TIo6AgRfjlCPTeZ8d0KY+aujXDX63JoHfsqank6wJh/rzEmAADAycqM81YTdT51PTXl5ttFthv0UZbUZ8Z3a69MqBQMTLbkvqilyqqFYsyTCrsAAACqy4xXrSbq1dT11NaEA+1VAhtDghHq+W0x58sDxzv2YOCqdh3pzgQAAADbO/VgoNQKCiYJBpoa3taa8wSCgQ+KWh5WGPPNHI4NAADgKGTGi1YT9WLqesZSrCQY/exyMe9OdynIjLPMeND891EHAx31HLz0P92yEAAAYHt5937yn09dzxSakGDUJeeZ8axozp9s+byz1nPOTiQYqH6Gf9fXBAAAYLEy4w+tJuoPU9ezJMX19Vtt/JgZP2w954enEAx01HTwJpjFeB/UqBEAAOAkZcYnrQbqk6nrWZLitc/M+NkWz/mo9fMfnVAwcF6znuIY3bIQAACgT9loTl3P0hR7PHy4xc/fCXJOJRiIWF81kBkPstlLYY+x3JkAAABgG+U161PXszS7vv4nHgzcuXXhIZ/LIfYtAAAAOFlNc3o2dR1LtcvrX+4JsWcwcF08bxZn1DPjsjyeA4KB94pw4TcDlAwAAADjyuIuEvsEA804q9s1ziIUiIjIjLcdocCvDhjP5QQAAACclmJPguf7BgNzlBkXxfFcHTjeb4pLE96rVSsAAABMIjP+2j4LfmLBwLPieJ5XGLN9OcGbGnUCAADAZDLj+z3X4R99MBCxts/AkwrjXRWv0VmFMgEAAGA6pxwMRERkxpMaoUAzVhkM3HtLSAAAAJi1zPhbTzDgtnyFjmDg8dQ1AQAAwMEy401HMGDn/ULH6/T/U9cEAAAAVWTGL4qm99XUNc1NZnwsGAAAAOCkZcYroUC/4s4EXicAAABYkiIYsA8DAAAALElmvCwuJ3g2dU0AAADAiDLjWjAAAAAAC5YZz4QCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA4V/ilvYw30ZUiAAAAABJRU5ErkJggg=='
+ });
+
+ // get an image for testing (just tap enter key)
+ $(document).keypress(function (e) {
+ if (e.keyCode === 13) {
+ console.log($('#wPaint').wPaint('image'));
+ }
+ });
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/static/js/wpaint/test/upload.php b/static/js/wpaint/test/upload.php
new file mode 100644
index 0000000..f0187b5
--- /dev/null
+++ b/static/js/wpaint/test/upload.php
@@ -0,0 +1,11 @@
+<?php
+
+$image = imagecreatefrompng($_POST['image']);
+$id = uniqid();
+
+imagealphablending($image, false);
+imagesavealpha($image, true);
+imagepng($image, 'uploads/wPaint-' . $id . '.png');
+
+// return image path
+echo '{"img": "/test/uploads/wPaint-' . $id . '.png"}';
diff --git a/static/js/wpaint/test/uploads/test1.png b/static/js/wpaint/test/uploads/test1.png
new file mode 100644
index 0000000..a0c6511
--- /dev/null
+++ b/static/js/wpaint/test/uploads/test1.png
Binary files differ
diff --git a/static/js/wpaint/test/uploads/test2.png b/static/js/wpaint/test/uploads/test2.png
new file mode 100644
index 0000000..68c25e0
--- /dev/null
+++ b/static/js/wpaint/test/uploads/test2.png
Binary files differ
diff --git a/static/js/wpaint/test/uploads/test3.png b/static/js/wpaint/test/uploads/test3.png
new file mode 100644
index 0000000..c92d3cc
--- /dev/null
+++ b/static/js/wpaint/test/uploads/test3.png
Binary files differ
diff --git a/static/js/wpaint/test/uploads/wPaint.png b/static/js/wpaint/test/uploads/wPaint.png
new file mode 100644
index 0000000..c19ab7f
--- /dev/null
+++ b/static/js/wpaint/test/uploads/wPaint.png
Binary files differ
diff --git a/static/js/wpaint/wPaint.jquery.json b/static/js/wpaint/wPaint.jquery.json
new file mode 100644
index 0000000..ab42ec5
--- /dev/null
+++ b/static/js/wpaint/wPaint.jquery.json
@@ -0,0 +1,38 @@
+{
+ "name": "wPaint",
+ "title": "wPaint jQuery Paint Plugin",
+ "description": "A jQuery paint plugin for a simple drawing surface that you can easily pop into your pages, similar to the basic windows paint program.",
+ "keywords": [
+ "websanova",
+ "wPaint",
+ "paint",
+ "canvas",
+ "html5"
+ ],
+ "version": "2.5.0",
+ "author": {
+ "name": "Websanova",
+ "email": "rob@websanova.com",
+ "url": "http://websanova.com"
+ },
+ "maintainers": [
+ {
+ "name": "Websanova",
+ "email": "rob@websanova.com",
+ "url": "http://websanova.com"
+ }
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/websanova/wPaint#license"
+ }
+ ],
+ "bugs": "https://github.com/websanova/wPaint/issues",
+ "homepage": "http://wpaint.websanova.com",
+ "docs": "https://github.com/websanova/wPaint#wpaintjs",
+ "download": "https://github.com/websanova/wPaint/tags",
+ "dependencies": {
+ "jquery": ">=1.5"
+ }
+}
diff --git a/static/js/wpaint/wPaint.min.css b/static/js/wpaint/wPaint.min.css
new file mode 100644
index 0000000..29de08b
--- /dev/null
+++ b/static/js/wpaint/wPaint.min.css
@@ -0,0 +1,66 @@
+.wPaint-menu{position:absolute !important;display:inline-block;*display:inline;zoom:1;line-height:0;z-index:99}
+.wPaint-menu-behind{z-index:98}
+.wPaint-menu-holder{position:relative;margin:0 1px 1px 0}
+.wPaint-menu-handle{display:inline-block;*display:inline;zoom:1}
+.wPaint-menu-icon{position:relative;vertical-align:top}
+.wPaint-menu-icon-img{position:relative;display:inline-block;*display:inline;zoom:1;background-repeat:no-repeat;overflow:hidden}
+.wPaint-menu-select-holder{position:absolute;left:1px;z-index:10;overflow:hidden}
+.wPaint-menu-select{position:relative;text-align:center;overflow-y:scroll;z-index:100}
+.wPaint-menu-select-option.first{border-top:0}
+.wPaint-menu-alignment-horizontal .wPaint-menu-icon{display:inline-block;*display:inline;zoom:1}
+.wPaint-menu-alignment-vertical .wPaint-menu-icon{display:block}
+.wPaint-status{position:absolute;display:none;right:0;bottom:0}
+.wPaint-modal-bg{position:absolute;left:0;top:0;width:100%;height:100%}
+.wPaint-modal{position:absolute;display:inline-block;*display:inline;zoom:1}
+.wPaint-modal-holder{display:inline-block;*display:inline;zoom:1;overflow:hidden}
+.wPaint-modal-content{overflow-y:scroll;width:100%;height:100%}
+.wPaint-modal-close{position:absolute}
+.wPaint-text-input{margin:0;padding:0;outline-width:0;word-wrap:break-word;overflow:hidden}
+.wPaint-modal-img-holder{line-height:0}
+.wPaint-modal-img{display:inline-block;*display:inline;zoom:1}
+.wPaint-menu-holder{border-style:solid;border-width:1px;-webkit-box-shadow:3px 3px 5px #555;box-shadow:3px 3px 5px #555}
+.wPaint-menu-handle{cursor:pointer}
+.wPaint-menu-icon{border-style:solid;border-width:1px;cursor:pointer}
+.wPaint-menu-icon.disabled{cursor:default}
+.wPaint-menu-icon.disabled .wPaint-menu-icon-img{opacity:.3;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";filter:alpha(opacity=30)}
+.wPaint-menu-icon-img{font-family:verdana;font-weight:bold;text-align:center}
+.wPaint-menu-select-holder{border-style:solid;border-width:1px;-webkit-box-shadow:1px 1px 2px #666;box-shadow:1px 1px 2px #666}
+.wPaint-menu-select{font-family:verdana;text-align:center}
+.wPaint-menu-select-option{border-top-style:solid;border-top-width:1px;cursor:pointer}
+.wPaint-menu-icon-select-img{background-repeat:no-repeat}
+.wPaint-menu-icon-group-arrow{position:absolute;right:1px;bottom:1px}
+.wPaint-menu-alignment-horizontal .wPaint-menu-handle{border-right-style:solid;border-right-width:1px}
+.wPaint-menu-alignment-vertical .wPaint-menu-handle{border-bottom-style:solid;border-bottom-width:1px}
+.wPaint-status{font-size:10px;font-family:verdana;line-height:10px;height:10px;background-color:#3a3a3a;color:#f0f0f0;padding:5px;opacity:.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50)}
+.wPaint-modal-bg{background-color:#3a3a3a;opacity:.8;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";filter:alpha(opacity=80)}
+.wPaint-modal-holder{height:100px;-webkit-box-shadow:3px 3px 5px #555;box-shadow:3px 3px 5px #555;-webkit-border-radius:5px;border-radius:5px;border-style:solid;border-width:2px;cursor:default}
+.wPaint-modal-close{right:-7px;top:-7px;-webkit-border-radius:10px;border-radius:10px;font-size:8px;line-height:14px;padding:0 4px;font-weight:bold;border-style:solid;border-width:2px;cursor:pointer}
+.wPaint-text-input{border:dotted #00f 1px;background:none}
+.wPaint-modal-img-holder{border:solid #333 1px;-webkit-border-radius:5px;border-radius:5px;margin:3px;padding:2px;cursor:pointer}
+.wPaint-modal-img{width:100px;-webkit-border-radius:4px;border-radius:4px;margin-bottom:0}
+.wPaint-theme-standard .wPaint-menu-holder{-webkit-border-radius:7px;border-radius:7px}
+.wPaint-theme-standard .wPaint-menu-select-holder{-webkit-border-radius:5px;border-radius:5px}
+.wPaint-theme-standard .wPaint-menu-icon{-webkit-border-radius:7px;border-radius:7px}
+.wPaint-theme-standard .wPaint-menu-icon-img{margin:6px 5px 5px 6px;width:18px;height:18px;line-height:18px;font-size:12px}
+.wPaint-theme-standard .wPaint-menu-colorpicker .wPaint-menu-icon-img{margin:3px 2px 2px 3px;width:24px;height:24px;-webkit-border-radius:5px;border-radius:5px}
+.wPaint-theme-standard .wPaint-menu-icon-group .wPaint-menu-select-option{padding:4px}
+.wPaint-theme-standard .wPaint-menu-icon-group-arrow{width:5px;height:3px;background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAADCAYAAABbNsX4AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK6wAACusBgosNWgAAABZ0RVh0Q3JlYXRpb24gVGltZQAwOC8xMS8xMyj8hykAAAAcdEVYdFNvZnR3YXJlAEFkb2JlIEZpcmV3b3JrcyBDUzbovLKMAAAAKElEQVQImV3IwQ0AMAyDQKerspZ3pa9IVXmdGMB8nbbzjrYTNWoA1xeQ3RPyxUyE/gAAAABJRU5ErkJggg==")}
+.wPaint-theme-standard .wPaint-menu-select{line-height:10px;font-size:10px;max-height:136px}
+.wPaint-theme-standard .wPaint-menu-select-option{max-width:50px;padding:4px 7px}
+.wPaint-theme-standard .wPaint-menu-icon-select-img{width:18px;height:18px}
+.wPaint-theme-standard .wPaint-menu-alignment-horizontal.wPaint-menu-nohandle .wPaint-menu-holder{padding-left:4px}
+.wPaint-theme-standard .wPaint-menu-alignment-horizontal .wPaint-menu-icon{margin:4px 5px 4px 0}
+.wPaint-theme-standard .wPaint-menu-alignment-horizontal .wPaint-menu-handle{width:30px;height:39px;margin-right:5px;border-top-left-radius:7px;border-bottom-left-radius:7px}
+.wPaint-theme-standard .wPaint-menu-alignment-vertical.wPaint-menu-nohandle .wPaint-menu-holder{padding-top:4px}
+.wPaint-theme-standard .wPaint-menu-alignment-vertical .wPaint-menu-icon{margin:0 4px 5px 4px}
+.wPaint-theme-standard .wPaint-menu-alignment-vertical .wPaint-menu-handle{width:39px;height:30px;margin-bottom:5px;border-top-left-radius:7px;border-top-right-radius:7px}
+.wPaint-theme-classic .wPaint-menu-holder{border-color:#dadada;background-color:#f0f0f0}
+.wPaint-theme-classic .wPaint-menu-handle{background-color:#dadada;-webkit-box-shadow:inset 1px 1px 3px #fff;box-shadow:inset 1px 1px 3px #fff;border-color:#dadada}
+.wPaint-theme-classic .wPaint-menu-icon{border-color:#b9b9b9;background-color:#b9b9b9;-webkit-box-shadow:inset 2px 2px 3px #eee,1px 1px 2px #666;box-shadow:inset 2px 2px 3px #eee,1px 1px 2px #666}
+.wPaint-theme-classic .wPaint-menu-icon.hover,.wPaint-theme-classic .wPaint-menu-icon.active{border-color:#9cf;background-color:#acf}
+.wPaint-theme-classic .wPaint-menu-icon-img{color:#696969}
+.wPaint-theme-classic .wPaint-menu-select-holder{border-color:#cacaca}
+.wPaint-theme-classic .wPaint-menu-select{color:#494949}
+.wPaint-theme-classic .wPaint-menu-select-option{-webkit-box-shadow:inset 2px 2px 3px #fff;box-shadow:inset 2px 2px 3px #fff;border-top-color:#cacaca;background-color:#f0f0f0}
+.wPaint-theme-classic .wPaint-menu-select-option:hover{-webkit-box-shadow:inset 1px 1px 1px #fff;box-shadow:inset 1px 1px 1px #fff;background-color:#9cf;color:#f0f0f0}
+.wPaint-theme-classic .wPaint-modal-close,.wPaint-theme-classic .wPaint-modal-holder{border-color:#3a3a3a;background-color:#f0f0f0}
diff --git a/static/js/wpaint/wPaint.min.js b/static/js/wpaint/wPaint.min.js
new file mode 100644
index 0000000..3ea04e6
--- /dev/null
+++ b/static/js/wpaint/wPaint.min.js
@@ -0,0 +1 @@
+/*! wPaint - v2.5.0 - 2014-03-01 */!function(a){"use strict";function b(b,c){this.$el=a(b),this.options=c,this.init=!1,this.menus={primary:null,active:null,all:{}},this.previousMode=null,this.width=this.$el.width(),this.height=this.$el.height(),this.ctxBgResize=!1,this.ctxResize=!1,this.generate(),this._init()}function c(a,b,c){this.wPaint=a,this.options=c,this.name=b,this.type=a.menus.primary?"secondary":"primary",this.docked=!0,this.dockOffset={left:0,top:0},this.generate()}b.prototype={generate:function(){function b(b){var c=b?b.capitalize():"",d="canvas"+c,e="ctx"+c;return f[d]=document.createElement("canvas"),f[e]=f[d].getContext("2d"),f["$"+d]=a(f[d]),f["$"+d].attr("class","wPaint-canvas"+(b?"-"+b:"")).attr("width",f.width+"px").attr("height",f.height+"px").css({position:"absolute",left:0,top:0}),f.$el.append(f["$"+d]),f["$"+d]}function c(a){a.preventDefault(),a.stopPropagation(),f.draw=!0,a.canvasEvent="down",f._closeSelectBoxes(),f._callShapeFunc.apply(f,[a])}function d(a){f.draw&&(a.canvasEvent="move",f._callShapeFunc.apply(f,[a]))}function e(a){f.draw&&(f.draw=!1,a.canvasEvent="up",f._callShapeFunc.apply(f,[a]))}if(this.init)return this;var f=this;b("bg"),b("").on("mousedown",c).bindMobileEvents(),b("temp").hide(),a(document).on("mousemove",d).on("mousedown",a.proxy(this._closeSelectBoxes,this)).on("mouseup",e),this.setTheme(this.options.theme)},_init:function(){var a=null,b=null;this.init=!0;for(a in this.options)b="set"+a.capitalize(),this[b]&&this[b](this.options[a]);this._fixMenus(),this.menus.primary._getIcon(this.options.mode).trigger("click")},resize:function(){var a=this.getBg(),b=this.getImage();this.width=this.$el.width(),this.height=this.$el.height(),this.canvasBg.width=this.width,this.canvasBg.height=this.height,this.canvas.width=this.width,this.canvas.height=this.height,this.ctxBgResize===!1&&(this.ctxBgResize=!0,this.setBg(a,!0)),this.ctxResize===!1&&(this.ctxResize=!0,this.setImage(b,"",!0,!0))},setTheme:function(a){var b,c;for(a=a.split(" "),this.$el.attr("class",(this.$el.attr("class")||"").replace(/wPaint-theme-.+\s|wPaint-theme-.+$/,"")),b=0,c=a.length;c>b;b++)this.$el.addClass("wPaint-theme-"+a[b])},setMode:function(a){this.setCursor(a),this.previousMode=this.options.mode,this.options.mode=a},setImage:function(b,c,d,e){function f(){var a=1,b=0,f=0,j=0,k=0,l=h.width,m=h.height;d||((h.width>g.width||h.height>g.height||g.options.imageStretch)&&(b=g.width/h.width,f=g.height/h.height,a=f>b?b:f,l=h.width*a,m=h.height*a),j=(g.width-l)/2,k=(g.height-m)/2),i.clearRect(0,0,g.width,g.height),i.drawImage(h,j,k,l,m),g[c+"Resize"]=!1,e||g._addUndo()}if(!b)return!0;var g=this,h=null,i="";c="ctx"+(c||"").capitalize(),i=this[c],window.rgbHex(b)?(i.clearRect(0,0,this.width,this.height),i.fillStyle=b,i.rect(0,0,this.width,this.height),i.fill()):(h=new Image,h.src=b.toString(),a(h).load(f))},setBg:function(a,b){return a?void this.setImage(a,"bg",b,!0):!0},setCursor:function(b){b=a.fn.wPaint.cursors[b]||a.fn.wPaint.cursors["default"],this.$el.css("cursor",'url("'+this.options.path+b.path+'") '+b.left+" "+b.top+", default")},setMenuOrientation:function(b){a.each(this.menus.all,function(a,c){c.options.aligment=b,c.setAlignment(b)})},getImage:function(b){var c=document.createElement("canvas"),d=c.getContext("2d");return b=b===!1?!1:!0,a(c).css({display:"none",position:"absolute",left:0,top:0}).attr("width",this.width).attr("height",this.height),b&&d.drawImage(this.canvasBg,0,0),d.drawImage(this.canvas,0,0),c.toDataURL()},getBg:function(){return this.canvasBg.toDataURL()},_displayStatus:function(b){var c=this;this.$status||(this.$status=a('<div class="wPaint-status"></div>'),this.$el.append(this.$status)),this.$status.html(b),clearTimeout(this.displayStatusTimer),this.$status.fadeIn(500,function(){c.displayStatusTimer=setTimeout(function(){c.$status.fadeOut(500)},1500)})},_showModal:function(a){function b(){d.remove(),e.remove(),c._createModal(a)}var c=this,d=this.$el.children(".wPaint-modal-bg"),e=this.$el.children(".wPaint-modal");d.length?e.fadeOut(500,b):this._createModal(a)},_createModal:function(b){function c(){f.fadeOut(500,d)}function d(){e.remove(),f.remove()}b=a('<div class="wPaint-modal-content"></div>').append(b.children());var e=a('<div class="wPaint-modal-bg"></div>'),f=a('<div class="wPaint-modal"></div>'),g=a('<div class="wPaint-modal-holder"></div>'),h=a('<div class="wPaint-modal-close">X</div>');h.on("click",c),f.append(g.append(b)).append(h),this.$el.append(e).append(f),f.css({left:this.$el.outerWidth()/2-f.outerWidth(!0)/2,top:this.$el.outerHeight()/2-f.outerHeight(!0)/2}),f.fadeIn(500)},_createMenu:function(a,b){return b=b||{},b.alignment=this.options.menuOrientation,b.handle=this.options.menuHandle,new c(this,a,b)},_fixMenus:function(){function b(b,d){var e=a(d),f=e.clone();f.appendTo(c.$el),f.outerHeight()===f.get(0).scrollHeight&&e.css({overflowY:"auto"}),f.remove()}var c=this,d=null;for(var e in this.menus.all)d=c.menus.all[e].$menu.find(".wPaint-menu-select-holder"),d.length&&d.children().each(b)},_closeSelectBoxes:function(a){var b,c;for(b in this.menus.all)c=this.menus.all[b].$menuHolder.children(".wPaint-menu-icon-select"),a&&(c=c.not(".wPaint-menu-icon-name-"+a.name)),c.children(".wPaint-menu-select-holder").hide()},_callShapeFunc:function(a){var b=this.$canvas.offset(),c=a.canvasEvent.capitalize(),d="_draw"+this.options.mode.capitalize()+c;a.pageX=Math.floor(a.pageX-b.left),a.pageY=Math.floor(a.pageY-b.top),this[d]&&this[d].apply(this,[a]),this.options["draw"+c]&&this.options["_draw"+c].apply(this,[a]),"Down"===c&&this.options.onShapeDown?this.options.onShapeDown.apply(this,[a]):"Move"===c&&this.options.onShapeMove?this.options.onShapeMove.apply(this,[a]):"Up"===c&&this.options.onShapeUp&&this.options.onShapeUp.apply(this,[a])},_stopPropagation:function(a){a.stopPropagation()},_drawShapeDown:function(a){this.$canvasTemp.css({left:a.PageX,top:a.PageY}).attr("width",0).attr("height",0).show(),this.canvasTempLeftOriginal=a.pageX,this.canvasTempTopOriginal=a.pageY},_drawShapeMove:function(b,c){var d=this.canvasTempLeftOriginal,e=this.canvasTempTopOriginal;c=c||2,b.left=b.pageX<d?b.pageX:d,b.top=b.pageY<e?b.pageY:e,b.width=Math.abs(b.pageX-d),b.height=Math.abs(b.pageY-e),b.x=this.options.lineWidth/2*c,b.y=this.options.lineWidth/2*c,b.w=b.width-this.options.lineWidth*c,b.h=b.height-this.options.lineWidth*c,a(this.canvasTemp).css({left:b.left,top:b.top}).attr("width",b.width).attr("height",b.height),this.canvasTempLeftNew=b.left,this.canvasTempTopNew=b.top,c=c||2,this.ctxTemp.fillStyle=this.options.fillStyle,this.ctxTemp.strokeStyle=this.options.strokeStyle,this.ctxTemp.lineWidth=this.options.lineWidth*c},_drawShapeUp:function(){this.ctx.drawImage(this.canvasTemp,this.canvasTempLeftNew,this.canvasTempTopNew),this.$canvasTemp.hide()},_drawDropperDown:function(a){var b={x:a.pageX,y:a.pageY},c=this._getPixel(this.ctx,b),d=null;d="rgba("+[c.r,c.g,c.b,c.a].join(",")+")",this.options[this.dropper]=d,this.menus.active._getIcon(this.dropper).wColorPicker("color",d)},_drawDropperUp:function(){this.setMode(this.previousMode)},_getPixel:function(a,b){var c=a.getImageData(0,0,this.width,this.height),d=c.data,e=4*(b.y*c.width+b.x);return{r:d[e],g:d[e+1],b:d[e+2],a:d[e+3]}}},c.prototype={generate:function(){this.$menu=a('<div class="wPaint-menu"></div>'),this.$menuHolder=a('<div class="wPaint-menu-holder wPaint-menu-name-'+this.name+'"></div>'),this.options.handle?this.$menuHandle=this._createHandle():this.$menu.addClass("wPaint-menu-nohandle"),"primary"===this.type?(this.wPaint.menus.primary=this,this.setOffsetLeft(this.options.offsetLeft),this.setOffsetTop(this.options.offsetTop)):"secondary"===this.type&&this.$menu.hide(),this.$menu.append(this.$menuHolder.append(this.$menuHandle)),this.reset(),this.wPaint.$el.append(this.$menu),this.setAlignment(this.options.alignment)},reset:function(){function b(a){d._appendItem(a)}var c,d=this,e=a.fn.wPaint.menus[this.name];for(c in e.items)this.$menuHolder.children(".wPaint-menu-icon-name-"+c).length||(e.items[c].name=c,e.items[c].img=d.wPaint.options.path+(e.items[c].img||e.img),b(e.items[c]))},_appendItem:function(a){var b=this["_createIcon"+a.icon.capitalize()](a);a.after?this.$menuHolder.children(".wPaint-menu-icon-name-"+a.after).after(b):this.$menuHolder.append(b)},setOffsetLeft:function(a){this.$menu.css({left:a})},setOffsetTop:function(a){this.$menu.css({top:a})},setAlignment:function(a){var b=this.$menu.css("left");this.$menu.attr("class",this.$menu.attr("class").replace(/wPaint-menu-alignment-.+\s|wPaint-menu-alignment-.+$/,"")),this.$menu.addClass("wPaint-menu-alignment-"+a),this.$menu.width("auto").css("left",-1e4),this.$menu.width(this.$menu.width()).css("left",b),"secondary"===this.type&&("horizontal"===this.options.alignment?this.dockOffset.top=this.wPaint.menus.primary.$menu.outerHeight(!0):this.dockOffset.left=this.wPaint.menus.primary.$menu.outerWidth(!0))},_createHandle:function(){function b(){e.docked=!1,e._setDrag()}function c(){a.each(e.$menu.data("ui-draggable").snapElements,function(a,b){var c=e.$menu.offset(),d=e.wPaint.menus.primary.$menu.offset();e.dockOffset.left=c.left-d.left,e.dockOffset.top=c.top-d.top,e.docked=b.snapping}),e._setDrag()}function d(){e._setIndex()}var e=this,f=a('<div class="wPaint-menu-handle"></div>');return this.$menu.draggable({handle:f}),"secondary"===this.type&&(this.$menu.draggable("option","snap",this.wPaint.menus.primary.$menu),this.$menu.draggable("option","start",b),this.$menu.draggable("option","stop",c),this.$menu.draggable("option","drag",d)),f.bindMobileEvents(),f},_createIconBase:function(b){function c(b){var c=a(b.currentTarget);c.siblings(".hover").removeClass("hover"),c.hasClass("disabled")||c.addClass("hover")}function d(b){a(b.currentTarget).removeClass("hover")}function e(){f.wPaint.menus.active=f}var f=this,g=a('<div class="wPaint-menu-icon wPaint-menu-icon-name-'+b.name+'"></div>'),h=a('<div class="wPaint-menu-icon-img"></div>'),i=h.realWidth(null,null,this.wPaint.$el);return g.attr("title",b.title).on("mousedown",a.proxy(this.wPaint._closeSelectBoxes,this.wPaint,b)).on("mouseenter",c).on("mouseleave",d).on("click",e),a.isNumeric(b.index)&&h.css({backgroundImage:"url("+b.img+")",backgroundPosition:-i*b.index+"px 0px"}),g.append(h)},_createIconGroup:function(b){function c(){h.children(".wPaint-menu-select-holder").is(":visible")||b.callback.apply(f.wPaint,[])}function d(){h.addClass("active").siblings(".active").removeClass("active")}function e(){h.attr("title",b.title).off("click.setIcon").on("click.setIcon",c),h.children(".wPaint-menu-icon-img").css(g),b.callback.apply(f.wPaint,[])}var f=this,g={backgroundImage:"url("+b.img+")"},h=this.$menuHolder.children(".wPaint-menu-icon-group-"+b.group),i=h.length,j=null,k=null,l=null,m=0;return i||(h=this._createIconBase(b).addClass("wPaint-menu-icon-group wPaint-menu-icon-group-"+b.group).on("click.setIcon",c).on("mousedown",a.proxy(this._iconClick,this))),m=h.children(".wPaint-menu-icon-img").realWidth(null,null,this.wPaint.$el),g.backgroundPosition=-m*b.index+"px center",j=h.children(".wPaint-menu-select-holder"),j.length||(j=this._createSelectBox(h),j.children().on("click",d)),l=a('<div class="wPaint-menu-icon-select-img"></div>').attr("title",b.title).css(g),k=this._createSelectOption(j,l).addClass("wPaint-menu-icon-name-"+b.name).on("click",e),b.after&&j.children(".wPaint-menu-select").children(".wPaint-menu-icon-name-"+b.after).after(k),i?void 0:h},_createIconGeneric:function(a){return this._createIconActivate(a)},_createIconActivate:function(a){function b(b){"generic"!==a.icon&&c._iconClick(b),a.callback.apply(c.wPaint,[b])}if(a.group)return this._createIconGroup(a);var c=this,d=this._createIconBase(a);return d.on("click",b),d},_isIconDisabled:function(a){return this.$menuHolder.children(".wPaint-menu-icon-name-"+a).hasClass("disabled")},_setIconDisabled:function(a,b){var c=this.$menuHolder.children(".wPaint-menu-icon-name-"+a);b?c.addClass("disabled").removeClass("hover"):c.removeClass("disabled")},_getIcon:function(a){return this.$menuHolder.children(".wPaint-menu-icon-name-"+a)},_iconClick:function(b){var c=a(b.currentTarget),d=this.wPaint.menus.all;for(var e in d)d[e]&&"secondary"===d[e].type&&d[e].$menu.hide();c.siblings(".active").removeClass("active"),c.hasClass("disabled")||c.addClass("active")},_createIconToggle:function(a){function b(){d.toggleClass("active"),a.callback.apply(c.wPaint,[d.hasClass("active")])}var c=this,d=this._createIconBase(a);return d.on("click",b),d},_createIconSelect:function(b){function c(c){h.children(".wPaint-menu-icon-img").html(a(c.currentTarget).html()),b.callback.apply(g.wPaint,[a(c.currentTarget).html()])}var d,e,f,g=this,h=this._createIconBase(b),i=this._createSelectBox(h);for(d=0,e=b.range.length;e>d;d++)f=this._createSelectOption(i,b.range[d]),f.on("click",c),b.useRange&&f.css(b.name,b.range[d]);return h},_createSelectBox:function(b){function c(a){a.stopPropagation(),g.hide()}function d(){i=setTimeout(function(){g.toggle()},200)}function e(){clearTimeout(i)}function f(){g.toggle()}var g=a('<div class="wPaint-menu-select-holder"></div>'),h=a('<div class="wPaint-menu-select"></div>'),i=null;return g.on("mousedown mouseup",this.wPaint._stopPropagation).on("click",c).hide(),g.css("horizontal"===this.options.alignment?{left:0,top:b.children(".wPaint-menu-icon-img").realHeight("outer",!0,this.wPaint.$el)}:{left:b.children(".wPaint-menu-icon-img").realWidth("outer",!0,this.wPaint.$el),top:0}),b.addClass("wPaint-menu-icon-select").append('<div class="wPaint-menu-icon-group-arrow"></div>').append(g.append(h)),b.hasClass("wPaint-menu-icon-group")?b.on("mousedown",d).on("mouseup",e):b.on("click",f),g},_createSelectOption:function(b,c){var d=b.children(".wPaint-menu-select"),e=a('<div class="wPaint-menu-select-option"></div>').append(c);return d.children().length||e.addClass("first"),d.append(e),e},_setSelectValue:function(a,b){this._getIcon(a).children(".wPaint-menu-icon-img").html(b)},_createIconColorPicker:function(a){function b(){"dropper"===e.wPaint.options.mode&&e.wPaint.setMode(e.wPaint.previousMode)}function c(b){a.callback.apply(e.wPaint,[b])}function d(){f.trigger("click"),e.wPaint.dropper=a.name,e.wPaint.setMode("dropper")}var e=this,f=this._createIconBase(a);return f.on("click",b).addClass("wPaint-menu-colorpicker").wColorPicker({mode:"click",generateButton:!1,dropperButton:!0,onSelect:c,onDropper:d}),f},_setColorPickerValue:function(a,b){this._getIcon(a).children(".wPaint-menu-icon-img").css("backgroundColor",b)},_createIconMenu:function(a){function b(){c.wPaint.setCursor(a.name);var b=c.wPaint.menus.all[a.name];b.$menu.toggle(),c.handle?b._setDrag():b._setPosition()}var c=this,d=this._createIconActivate(a);return d.on("click",b),d},_setDrag:function(){var b=this.$menu,c=null,d=null;b.is(":visible")&&(this.docked&&(c=d=a.proxy(this._setPosition,this),this._setPosition()),this.wPaint.menus.primary.$menu.draggable("option","drag",c),this.wPaint.menus.primary.$menu.draggable("option","stop",d))},_setPosition:function(){var a=this.wPaint.menus.primary.$menu.position();this.$menu.css({left:a.left+this.dockOffset.left,top:a.top+this.dockOffset.top})},_setIndex:function(){var a=this.wPaint.menus.primary.$menu.offset(),b=this.$menu.offset();b.top<a.top||b.left<a.left?this.$menu.addClass("wPaint-menu-behind"):this.$menu.removeClass("wPaint-menu-behind")}},a.support.canvas=document.createElement("canvas").getContext,a.fn.wPaint=function(c,d){function e(){return a.support.canvas?a.proxy(f,this)():(a(this).html("Browser does not support HTML5 canvas, please upgrade to a more modern browser."),!1)}function f(){var d=a.data(this,"wPaint");return d||(d=new b(this,a.extend(!0,{},c)),a.data(this,"wPaint",d)),d}function g(){var b=a.data(this,"wPaint");b&&(b[c]?b[c].apply(b,[d]):void 0!==d?(b[i]&&b[i].apply(b,[d]),b.options[c]&&(b.options[c]=d)):h.push(b[i]?b[i].apply(b,[d]):b.options[c]?b.options[c]:void 0))}if("string"==typeof c){var h=[],i=(d?"set":"get")+c.charAt(0).toUpperCase()+c.substring(1);return this.each(g),h.length?1===h.length?h[0]:h:this}return c=a.extend({},a.fn.wPaint.defaults,c),c.lineWidth=parseInt(c.lineWidth,10),c.fontSize=parseInt(c.fontSize,10),this.each(e)},a.fn.wPaint.extend=function(a,d){function e(c){if(d[c]){var e=b.prototype[c],f=a[c];d[c]=function(){e.apply(this,arguments),f.apply(this,arguments)}}else d[c]=a[c]}var f;d="menu"===d?c.prototype:b.prototype;for(f in a)e(f)},a.fn.wPaint.menus={},a.fn.wPaint.cursors={},a.fn.wPaint.defaults={path:"/",theme:"standard classic",autoScaleImage:!0,autoCenterImage:!0,menuHandle:!0,menuOrientation:"horizontal",menuOffsetLeft:5,menuOffsetTop:5,bg:null,image:null,imageStretch:!1,onShapeDown:null,onShapeMove:null,onShapeUp:null}}(jQuery),function(){String.prototype.capitalize||(String.prototype.capitalize=function(){return this.slice(0,1).toUpperCase()+this.slice(1)})}(),function(a){a.fn.realWidth=function(b,c,d){var e=null,f=null,g=null;return b="inner"===b||"outer"===b?b:"",g=""===b?"width":b+"Width",c=c===!0?!0:!1,f=a(this).clone().css({position:"absolute",left:-1e4}).appendTo(d||"body"),e=c?f[g](c):f[g](),f.remove(),e},a.fn.realHeight=function(b,c,d){var e=null,f=null,g=null;return b="inner"===b||"outer"===b?b:"",g=""===b?"height":b+"Height",c=c===!0?!0:!1,f=a(this).clone().css({position:"absolute",left:-1e4}).appendTo(d||"body"),e=c?f[g](c):f[g](),f.remove(),e},a.fn.bindMobileEvents=function(){a(this).on("touchstart touchmove touchend touchcancel",function(){var a=event.changedTouches||event.originalEvent.targetTouches,b=a[0],c="";switch(event.type){case"touchstart":c="mousedown";break;case"touchmove":c="mousemove",event.preventDefault();break;case"touchend":c="mouseup";break;default:return}var d=document.createEvent("MouseEvent");d.initMouseEvent(c,!0,!0,window,1,b.screenX,b.screenY,b.clientX,b.clientY,!1,!1,!1,!1,0,null),b.target.dispatchEvent(d)})}}(jQuery); \ No newline at end of file