separated Web from Mobile

This commit is contained in:
Mahdi Dibaiee
2014-02-07 15:50:19 +03:30
parent 8af0ac91b3
commit ab58829df2
162 changed files with 2608 additions and 31 deletions

20
Web/LICENSE Normal file
View File

@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2013 Mahdi Dibaiee
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

4
Web/README.md Normal file
View File

@ -0,0 +1,4 @@
Brush
=====
An image manipulation tool written in Javascript

90
Web/css/color-picker.css Normal file
View File

@ -0,0 +1,90 @@
/* Purty Picker Copyright 2013 Jayden Seric (MIT license): https://github.com/jaydenseric/Purty-Picker */
/* Core: No touchy! */
.color-picker .spectrum {
position: relative;
/* To position pin, luminosity filter */
background: linear-gradient(gray, transparent), linear-gradient(90deg, red, #ff2b00, #ff5500, #ff8000, #ffaa00, #ffd500, yellow, #d4ff00, #aaff00, #80ff00, #55ff00, #2bff00, lime, #00ff2b, #00ff55, #00ff80, #00ffaa, #00ffd5, cyan, #00d4ff, #00aaff, #007fff, #0055ff, #002bff, blue, #2a00ff, #5500ff, #7f00ff, #aa00ff, #d400ff, magenta, #ff00d4, #ff00aa, #ff0080, #ff0055, #ff002b, red);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Prevent pin interaction causing content selection */
cursor: crosshair;
}
.color-picker .spectrum.active {
cursor: none;
}
.color-picker .spectrum.active .pin {
cursor: none;
}
.color-picker .spectrum > div {
/* Luminosity filter */
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.color-picker .spectrum .pin {
position: absolute;
cursor: move;
}
/* Customization: Default skin */
.color-picker {
margin: 20px;
padding: 11px;
border: 1px solid #e3e3e3;
border-radius: 4px;
background-color: #f5f5f5;
}
.color-picker .color,
.color-picker .luminosity {
-moz-box-sizing: border-box;
box-sizing: border-box;
display: block;
width: 100%;
}
.color-picker .format {
display: block;
margin: 0 auto 10px auto;
}
.color-picker .color {
-webkit-appearance: none;
border: 0;
border-radius: 2px;
padding: 10px;
text-align: center;
font-size: 11px;
letter-spacing: 1px;
font-family: Consolas, Monaco, 'Andale Mono', monospace;
color: rgba(0, 0, 0, 0.6);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);
transition: color 0.2s;
}
.color-picker .color.dark {
color: rgba(255, 255, 255, 0.7);
}
.color-picker .spectrum {
height: 150px;
/* Arbitary but required */
overflow: hidden;
/* Prevent pin overflowing container */
border-radius: 2px;
margin: 10px 0;
}
.color-picker .spectrum > div {
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);
}
.color-picker .spectrum .pin {
margin-left: -4px;
margin-top: -4px;
width: 4px;
height: 4px;
border: 2px solid white;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.4);
border-radius: 100%;
}
.color-picker .luminosity {
margin: 0;
}

16
Web/css/fonts.less Normal file
View File

@ -0,0 +1,16 @@
@font-face {
font-family: 'MozTT-Regular';
src: url('fonts/MozTT-Regular.ttf');
}
@font-face {
font-family: 'MozTT-Light';
src: url('fonts/MozTT-Light.ttf');
}
@font-face {
font-family: 'MozTT-Medium';
src: url('fonts/MozTT-Medium.ttf');
}
@font-face {
font-family: 'MozTT-Bold';
src: url('fonts/MozTT-Bold.ttf');
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 B

BIN
Web/css/imgs/clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
Web/css/imgs/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
Web/css/imgs/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

BIN
Web/css/imgs/redo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
Web/css/imgs/settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
Web/css/imgs/undo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

266
Web/css/main.less Normal file
View File

@ -0,0 +1,266 @@
@import 'fonts';
html, body {
margin: 0;
font-size: 10px;
overflow: hidden;
}
*::-moz-focus-inner {
border: none;
}
*:focus {
outline: none;
}
.hidden {
display: none;
visibility: none;
}
div#container {
position: absolute;
}
canvas {
position: absolute;
top: 0;
left: 0;
}
.separator {
display: block;
height: 4.8rem;
width: 0.1rem;
&.long {
background: url('imgs/div_line_lg_black.png');
}
&.small {
background: url('imgs/div_line_sm_black.png');
}
&.left {
float: left;
}
&.right {
float: right;
}
&.menu {
position: relative;
left: -3rem;
}
}
.overlay {
z-index: 9999;
position: absolute;
left: 0;
top: 5.3rem;;
}
button {
-moz-appearance: none;
z-index: 1;
position: relative;
border: none;
}
.close {
display: block;
width: 2rem;
height: 2rem;
padding: 0 0 0.2rem 0.2rem;
font-size: 10pt;
border: 1px solid rgb(227, 227, 227);
border-radius: 50%;
position: absolute;
text-align: center;
top: -2%;
left: 97%;
}
.picker, .about {
font-family: 'MozTT-Light';
width: 30rem;
height: 24.6rem;
position: absolute;
left: 50%;
top: 50%;
margin-top: -12.3rem;
margin-left: -15rem;
.color-picker {
margin: 0;
}
}
.about {
background: #262626;
padding: 1rem 2rem;;
height: 23rem;
margin-top: -11.5rem;
margin-left: -17rem;
border-radius: 0.2rem;
color: white;
box-shadow: 0 0 0.3rem black;
a, a:link, a:visited, a:active {
color: white;
}
.close {
background: #262626;
color: white;
border: 1px solid gray;
}
p {
font-size: 11pt;
}
span {
font-size: 8pt;
}
}
header {
width: 100%;
height: 5.3rem;
background: url('imgs/header_bg_black.png');
button {
width: 5rem;
height: 5rem;
}
.menu {
background: url('imgs/menu.png') -12px center no-repeat;
float: left;
&:active {
background: url('imgs/menu.png') -12px center no-repeat, url('imgs/bg_overlay_pressed_1.png') left no-repeat;
}
}
.save {
background: url('imgs/download.png') center center no-repeat;
float: right;
&:active {
background: url('imgs/download.png') center center no-repeat, url('imgs/bg_overlay_pressed_2.png') center center;
}
}
#title {
color: white;
font-size: 11pt;
font-family: 'MozTT-Regular';
float: left;
margin: 1.5rem 0;
position: relative;
left: -2rem;
}
}
#menu {
height: 100%;
width: 15rem;
background: #262626;
position: absolute;
left: -15rem;
top: 5rem;
color: white;
font-family: 'MozTT-Light';
font-size: 8pt;
transition: left 0.2s ease-out;
border-collapse: collapse;
overflow: hidden;
&.pulled {
left: 0;
transition: left 0.2s ease-out;
}
button[id^='set'], p, .bottom button {
background: none;
display: block;
width: 75%;
color: white;
text-align: left;
margin: 1rem 2.5rem;
font-family: 'MozTT-Light';
font-size: 8pt;
padding: 0 0.6rem;
cursor: pointer;
}
span {
float: right;
font-size: 7pt;
}
div[role='slider'] {
width: 60%;
float: right;
margin: 0 2rem 0 0;
div {
overflow: visible;
button {
margin-top: -3.4rem;
left: 0%;
}
}
}
hr {
clear: both;
padding: 0.7rem 0;
margin-bottom: 0.7rem;
border: none;
border-bottom: 1px solid rgba(255,255,255,0.3);
}
*[class^='icon'] {
display: block;
margin: 1rem 0.5rem;
&:nth-of-type(2) {
padding-top: 0.5rem;
}
&:before {
content: '';
background-size: 2rem;
width: 2rem;
height: 2rem;
display: block;
float: left;
margin: -0.3rem 0.5rem 0 0;
}
}
.icon-settings:before {
background-image: url('imgs/settings.png');
}
.icon-clear:before {
background-image: url('imgs/clear.png');
}
.icon-undo:before {
background-image: url('imgs/undo.png');
}
.icon-redo:before {
background-image: url('imgs/redo.png');
}
.options {
display: block;
margin-top: 1rem;
}
.bottom {
position: absolute;
bottom: 5rem;
width: 100%;
button[class^='icon'] {
margin-left: 3.5rem;
}
button {
margin-left: 5rem;
}
}
}

80
Web/css/seekbars.css Normal file
View File

@ -0,0 +1,80 @@
/* ----------------------------------
* Seekbars
* ---------------------------------- */
div[role="slider"] {
position: relative;
height: 3.5rem;
}
div[role="slider"] > div {
display: block;
padding: 0;
overflow-y: hidden;
position: relative;
height: 100%;
}
div[role="slider"] progress {
width: 100%;
background: #000;
border: none;
height: 0.1rem;
display: block;
border-radius: 0;
margin-top: 1.9rem;
}
div[role="slider"] progress::-moz-progress-bar {
background: #01c5ed;
height: 0.6rem;
margin-top: -0.3rem;
border-radius: 0;
}
div[role="slider"] > label {
font-size: 1.5rem;
line-height: 3.8rem;
font-family: sans-serif;
color: #00aacb;
float: right;
padding: 0 0 0 1rem;
height: 3.5rem;
width: auto;
}
div[role="slider"] label:first-of-type {
float: left;
padding: 0 1rem 0 0;
}
div[role="slider"] > label.icon {
width: 3rem;
height: 3rem;
margin-top: 0.5rem;
font-size: 0;
background: no-repeat right top / 3rem auto;
}
div[role="slider"] > label.icon:first-of-type {
background-position: top left;
}
div[role="slider"] button {
width: 3.2rem;
height: 3.2rem;
background: url(seekbars/images/ui/handler.png) no-repeat center center / 3rem auto;
font: 0/0 a;
position: absolute;
top: 50%;
left: 0;
margin: -1.5rem 0 0 -1.6rem;
border-radius: 3.2rem;
border: solid 0.1rem transparent;
transition: border 0.15s ease;
padding: 0;
z-index: 10;
}
div[role="slider"] button:active {
border: solid 0.5rem #01c5ed;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

View File

@ -0,0 +1,79 @@
/* ----------------------------------
* Seekbars
* ---------------------------------- */
div[role="slider"] {
position: relative;
height: 3.5rem;
}
div[role="slider"] > div {
display: block;
overflow: hidden;
padding: 0;
position: relative;
height: 100%;
}
div[role="slider"] progress {
width: 100%;
background: #000;
border: none;
height: 0.1rem;
display: block;
border-radius: 0;
margin-top: 1.9rem;
}
div[role="slider"] progress::-moz-progress-bar {
background: #01c5ed;
height: 0.6rem;
margin-top: -0.3rem;
border-radius: 0;
}
div[role="slider"] > label {
font-size: 1.5rem;
line-height: 3.8rem;
font-family: sans-serif;
color: #00aacb;
float: right;
padding: 0 0 0 1rem;
height: 3.5rem;
width: auto;
}
div[role="slider"] label:first-of-type {
float: left;
padding: 0 1rem 0 0;
}
div[role="slider"] > label.icon {
width: 3rem;
height: 3rem;
margin-top: 0.5rem;
font-size: 0;
background: no-repeat right top / 3rem auto;
}
div[role="slider"] > label.icon:first-of-type {
background-position: top left;
}
div[role="slider"] button {
width: 3.2rem;
height: 3.2rem;
background: url(seekbars/images/ui/handler.png) no-repeat center center / 3rem auto;
font: 0/0 a;
position: absolute;
top: 50%;
left: 0;
margin: -1.5rem 0 0 -1.6rem;
border-radius: 3.2rem;
border: solid 0.1rem transparent;
transition: border 0.15s ease;
padding: 0;
}
div[role="slider"] button:active {
border: solid 0.5rem #01c5ed;
}

94
Web/css/switches.css Normal file
View File

@ -0,0 +1,94 @@
/* ----------------------------------
* CHECKBOXES / RADIOS
* ---------------------------------- */
label.pack-checkbox,
label.pack-radio,
label.pack-switch {
display: inline-block;
vertical-align: middle;
width: 5rem;
height: 5rem;
position: relative;
background: none;
}
label.pack-checkbox input,
label.pack-radio input,
label.pack-switch input {
margin: 0;
opacity: 0;
position: absolute;
top: 0;
left: 0;
}
label.pack-checkbox input ~ span:after,
label.pack-radio input ~ span:after {
content: '';
position: absolute;
left: 50%;
top: 50%;
margin: -1.1rem 0 0 -1.1rem;
width: 2.2rem;
height: 2.2rem;
pointer-events: none;
}
label.pack-checkbox input ~ span:after {
background: url(switches/images/check/default.png) no-repeat center top / 2.2rem auto;
}
label.pack-radio input ~ span:after {
background: url(switches/images/radio/default.png) no-repeat center top / 2.2rem auto;
}
label.pack-checkbox input:checked ~ span:after,
label.pack-radio input:checked ~ span:after,
label.pack-switch input:checked ~ span:after {
background-position: center bottom;
}
/* 'Dangerous' switches */
label.pack-checkbox.danger input ~ span:after {
background-image: url(switches/images/check/danger.png);
}
label.pack-radio.danger input ~ span:after {
background-image: url(switches/images/radio/danger.png);
}
/* ----------------------------------
* ON/OFF SWITCHES
* ---------------------------------- */
label.pack-switch input ~ span:after {
content: '';
position: absolute;
right: 0;
top: 50%;
width: 6rem;
margin: -1.4rem 0rem 0rem;
height: 2.7rem;
pointer-events: none;
border-radius: 1.35rem;
overflow: hidden;
background: #e6e6e6 url(switches/images/switch/background_off.png) no-repeat -3.2rem 0rem / 9.2rem 2.7rem;
transition: background 0.2s ease;
}
/* switch: 'ON' state */
label.pack-switch input:checked ~ span:after {
background: #e6e6e6 url(switches/images/switch/background.png) no-repeat 0rem 0rem / 9.2rem 2.7rem;
}
/* switch: disabled state */
label.pack-switch input:disabled ~ span:after {
opacity: 0.4;
}
label.pack-switch input.uninit ~ span:after {
transition: none;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 755 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

203
Web/css/value_selector.css Normal file
View File

@ -0,0 +1,203 @@
/* ----------------------------------
* Value selector (Single & Multiple)
* ---------------------------------- */
/* Main dialog setup */
form[role="dialog"][data-type="value-selector"] {
background: url(value_selector/images/ui/pattern.png) repeat left top, url(value_selector/images/ui/gradient.png) no-repeat left top / 100% 100%;
overflow: hidden;
position: absolute;
z-index: 100;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding: 0 0 7rem;
color: #fff;
font-family: sans-serif;
}
form[role="dialog"][data-type="value-selector"] > section {
padding: 0 1.5rem 0;
-moz-box-sizing: padding-box;
width: 100%;
height: 100%;
}
form[role="dialog"][data-type="value-selector"] h1 {
font-weight: 400;
font-size: 1.9rem;
line-height: 4.8rem;
color: #fff;
border-bottom: 0.1rem solid #616262;
background: rgba(0 ,0, 0, .2);
margin: 0 -1.5rem;
padding: 0 3rem 1rem;
height: 4.8rem;
-moz-box-sizing: border-box;
}
/* Specific component code */
form[role="dialog"][data-type="value-selector"] [role="listbox"] {
position: relative;
padding: 0;
margin: 0 -1.5rem;
max-height: calc(100% - 5rem);
overflow: auto;
border-top: solid 0.1rem #222323;
}
form[role="dialog"][data-type="value-selector"] .scrollable:before {
content: "";
display: block;
position: absolute;
pointer-events: none;
top: 4.8rem;
left: 0;
right: 0;
bottom: 6.9rem;
background: url(value_selector/images/ui/shadow.png) repeat-x left top, url(value_selector/images/ui/shadow-invert.png) repeat-x left bottom;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li {
margin: 0;
padding: 0 1.5rem;
height: auto;
list-style: none;
position: relative;
font-weight: lighter;
font-size: 2.2rem;
line-height: 3.9rem;
color: #fff;
transition: background-color 0.2s ease;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li:first-child label {
border-top-color: transparent;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li label {
outline: none;
display: block;
color: #fff;
border-top: 0.1rem solid #666;
border-bottom: 0.1rem solid #000;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li:last-child label {
border-bottom-color: transparent;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li label span {
display: block;
padding: 1rem 1.5rem;
line-height: 4rem;
word-wrap: break-word;
}
/* Pressed status */
form[role="dialog"][data-type="value-selector"] [role="listbox"] li:active {
background-color: #00ABCC;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li:active label {
border-color: transparent;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li:active + li label {
border-top-color: #000;
}
form[role="dialog"][data-type="value-selector"] [role="listbox"] li:active label span {
color: #fff !important;
background-image: none;
}
/* Checked status */
form[role="dialog"][data-type="value-selector"] [role="listbox"] li[aria-selected="true"]:not([data-input]) span {
padding-right: 2.6rem;
margin-right: 1.2rem;
color: #00abcd;
background: transparent url(value_selector/images/icons/checked.png) no-repeat 100% 50%;
background-size: 2rem;
}
/* Menu & buttons setup */
form[role="dialog"][data-type="value-selector"] menu {
white-space: nowrap;
margin: 0;
padding: 1.5rem;
border-top: solid 0.1rem rgba(255, 255, 255, 0.1);
background: #2d2d2d url(value_selector/images/ui/pattern.png) repeat left top;
display: block;
overflow: hidden;
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
form[role="dialog"][data-type="value-selector"] menu button::-moz-focus-inner {
border: none;
outline: none;
}
form[role="dialog"][data-type="value-selector"] menu button {
width: calc((100% - 1rem) / 2);
height: 3.8rem;
margin: 0 0 1rem;
padding: 0 1.5rem;
-moz-box-sizing: border-box;
display: inline-block;
vertical-align: middle;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
background: #fafafa url(value_selector/images/ui/default.png) repeat-x left bottom/ auto 100%;
border: 0.1rem solid #a6a6a6;
border-radius: 0.3rem;
font-weight: 500;
font-size: 1.6rem;
line-height: 3.8rem;
color: #333;
text-align: center;
text-shadow: 0.1rem 0.1rem 0 rgba(255,255,255,0.3);
text-decoration: none;
outline: none;
}
/* Press (default & affirmative) */
form[role="dialog"][data-type="value-selector"] menu button:active,
form[role="dialog"][data-type="value-selector"] menu button.affirmative:active {
border-color: #008aaa;
background: #008aaa;
color: #333;
}
/* affirmative */
form[role="dialog"][data-type="value-selector"] menu button.affirmative {
background-image: url(value_selector/images/ui/affirmative.png);
background-color: #00caf2;
border-color: #008eab;
}
form[role="dialog"][data-type="value-selector"] menu button:last-child {
margin-left: 1rem;
}
form[role="dialog"][data-type="value-selector"] menu button,
form[role="dialog"][data-type="value-selector"] menu button:first-child {
margin: 0;
}
form[role="dialog"][data-type="value-selector"] menu button.full {
width: 100%;
}
/* Right to left tweaks */
html[dir="rtl"] #value-selector li input:checked + span,
html[dir="rtl"] #value-selector li[aria-selected="true"] span {
padding-left: 2.6rem;
margin-left: 1.2rem;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
Web/img/icons/icon120.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
Web/img/icons/icon128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

BIN
Web/img/icons/icon16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

BIN
Web/img/icons/icon2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

102
Web/img/icons/icon2.svg Normal file
View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="60"
height="60"
id="svg3029"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="icon2.svg"
inkscape:export-filename="/home/mahdi/Documents/Workshop/Mobile Editor/img/icons/icon128.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192">
<defs
id="defs3031" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-103.49318"
inkscape:cy="83.371075"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:grid-bbox="true"
inkscape:document-units="px"
inkscape:window-width="1600"
inkscape:window-height="876"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata3034">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer"
transform="translate(0,12)">
<path
sodipodi:type="arc"
style="fill:#636363;fill-opacity:1;stroke:none"
id="path3037"
sodipodi:cx="31.428572"
sodipodi:cy="29.285715"
sodipodi:rx="26.428572"
sodipodi:ry="26.428572"
d="m 57.857143,29.285715 c 0,14.596097 -11.832474,26.428572 -26.428571,26.428572 C 16.832475,55.714287 5,43.881812 5,29.285715 5,14.689618 16.832475,2.8571434 31.428572,2.8571434 c 14.596097,0 26.428571,11.8324746 26.428571,26.4285716 z"
transform="matrix(1.0972973,0,0,1.0972973,-4.4864869,-14.135136)" />
<path
style="fill:#dedede;fill-opacity:1;stroke:#383838;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 40.415998,-0.2045792 c 0,0 -22.715805,23.0693572 -23.422911,25.0139012 -0.707107,1.944544 -2.740039,7.601398 -2.032932,8.485281 0.707106,0.883883 7.689786,-1.502602 9.015611,-2.828427 C 25.301591,29.140351 47.60072,6.06032 47.840618,4.833556 48.06427,3.68987 41.877086,-1.6684275 40.415998,-0.2045792 z"
id="path3054"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cssssc" />
<path
style="fill:#9e9e9e;fill-opacity:1;stroke:none"
d="m 44.875383,3.203193 c 0,0 -23.929105,24.058149 -24.015804,24.932991 -0.0867,0.874841 1.387194,2.71201 1.820692,2.187104 C 23.11377,29.798383 46.435977,5.9152018 46.522677,5.0403605 46.609378,4.1655182 45.222182,3.2906768 44.875383,3.203193 z"
id="path3841"
inkscape:connector-curvature="0" />
<path
style="fill:#c0c0c0;fill-opacity:1;stroke:none"
d="m 42.401427,1.6217284 c 0,0 -23.399153,24.3933116 -23.394823,24.6432736 0.0043,0.249963 1.094444,1.292086 1.650364,0.907398 0.55592,-0.384687 23.207727,-24.0757977 23.264805,-24.3893335 0.05708,-0.3135357 -1.2693,-1.1031781 -1.520346,-1.1613381 z"
id="path3861"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccssc" />
<path
style="fill:#494949;fill-opacity:1;stroke:none"
d="m 15.695313,42.429687 c 0,0 -0.515625,1.960938 -0.359375,2.539063 0.0078,0 0.141085,0.342965 2.430147,-0.344535 -0.01563,0.0078 -0.647057,-2.041553 -2.070772,-2.194528 z"
id="path3865"
inkscape:connector-curvature="0"
transform="translate(0,-12)"
sodipodi:nodetypes="cccc" />
<image
y="-11.715099"
x="0.21543235"
id="image3962"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAABHNCSVQICAgIfAhkiAAABwNJREFU aIHlm01MG+kZx3/vjIevNTEfNhvA3RqWbmirqKcGlMKlbZRL0kMPrSqUgIxCyIVISc45IUWRckmv vVXNIWqVNjRqN60qVZuqXdE0yiZebdRslV3YJSZmiw3YgzHD9PB6YuPYMLbHHqT+pUfGlud9n5+f 93nejxmEaZr8P0lx24F6y1ODNkWJz/cbSpVeV5acAhZ5ZuZZOSr8vtWeUkWbb0hUmcOWQwLYccqp In3kg1v9VNZYFcBq1okdwKi0kXr3WQmwADTkr7yN8xG1078n+5opt/9ygVUk7HbW3JQnaxnKiHY5 wB4kbBo5pA6CFKARCW0rAHbn4YasHSRYkL6kyfm3r+wAW43pHCxYSzu3bt3afPbsWfPc3Fzzfl/e b0hrQDOwwQGBFUJYRUvLvqqAEggExNmzZ72apsWuXbuWLHX9XhFWgbeAFAcAVgjRIIRoBToAH9CC HHkqIGKxGHNzc7qmaW/Pzs6WHN6lgAXQCmziYjUWUi1CiE4kZBO5hc4b9vz58535+fktRVF6rl69 WnSpWgq4Jfu66SiBTVmgQCfgJRtFO3b//v2tly9fehobG/3F2i4GbA3ldadB7EgI0YAEbaUM0Hy7 c+dOUlGUrps3b74xtIsB+5AVuV7LReB1VH3IHLVWUhXZ0tKSGYlENtPpdG9hP4XAVlUuWeVqISGE B/AjU6li0Hy7e/eurqpq2/Xr15vy+yoE9iFh61aVhRCNQAD5YzsCC4hkMkkkEkl5vd5dUVYK/vZS x9zNFiY/uV2Qo3bv3j0d8M/Pz6tWn/nAXmRVrkvu5lXhktNMtbaysmJGo9HMw4cPA1a/+cDWcK65 hBDNyMg6HtVCe/z4sa4oymGrbwtYIAtGzYGz004XNYxsvj148CCtqmr77du3FcidabUgt1g1LVZC CAV4G5mzdVEikWB1ddU0DKMd+MqK8FvUZ1UVQO5faz6U8y0ajW4h53fqBiyE8CLrRF1hAWVxcTGj adqhfOBmYKuGsAKZt67o1atXr4GtHG6khsDI6cfWiUQttLi4aGRH2C7gmmwDs4XKmm9d0fLysqko ShPkgDVqV6E7s+27plQqZS1hXwNb2zBHz5izuRvAxegCaJomFEXxQA7YJHfG66R8uJi7ltra2jxm 9vDOAt6hNsAduBxdgI6ODs0wjF3AGWTh0p3qJFusfMhUcVWHDx9uUFV1E3LAm8jFR9zBfqwjGtcV DAZbDMNYgxzwBjIaXzrYj48DAhwKhXymaX4OufyKI6cPJ9VKHXZDdqynp6dN1/Uo5CL8X6At+96p BYiXA1CwfD6f6vf7W6PR6Bewu0onkFu3qoe1EELD5cWGpRMnTnSaprk8MzOTgd3PeHwJfB1n8ti6 Q+C6jh071qPr+iPrfb5Ti0AvcnqqVg24sA0stK6ursa+vj5/Op1+Ugx4C1gC3nMAuKqDdKdsbGys d3t7+9Pz58+nigEDfAx8m+rzz/Xoer1ez9DQUH88Hv8g37HC57TiwDLwTeAJ1cnVHD537lzIMIyF 6enpL/I/L+bUQ+AouTuIlcjExaEcCoWaRkdH+3Rdv1voWDHgdeATYKQK4AwuDudLly4dTaVSH05O TsbsAAN8hFwaDlYInHYLNhwOv9Pb2+tJJpN/LOZYKWAD+BNwHHmHoFzpbsAODw+3nT59ejAej/9i amqq6FZ3r8KSAD4ATiGXibZlmqaB3IHVLW8HBgaar1y5ciyRSPw6HA6/LOXbfpX0U+AR8GPkUW45 WqsXbDAYbJqdnf1eKpV6f3x8/B97OWVn6ngC/Bv4KXDIPi+r9YAdHBxsuXHjxohpmn8/c+bM+/s5 Zfd56Q+RK7GfAb8FXtm4JkaN5+Ljx4/7Ll++PKTr+h/GxsZ+b+each4Qf4Q8KPgJ8ABZyUvKNM24 EGKT8lPBli5cuBA6derUe7FY7Ffj4+N/s3tdJY8PdwA/Qha1vyBztXjjQnwH+Ea5HeylI0eOtMzM zBwNBoPEYrGfT05OLpZzfaUPiKvAEPBdYB65OntjGhBCtAM/rKSDQvl8PnV6evrdkZGRd9fX1/+8 vr7+m1JTz16q9l8A2oDvA18D/pW1XSefQogfUMXxUXd3d8PExET/8PBwv2EYz1ZXV38ZDoeXKm2v WmBLXciIHwE+B54CL4C0EKKXMpepnZ2dnpMnT3aNjo6+EwqFOjc2Nj7a2Nj43cTExH+qddQpYEvN wLeQS9JeYAVYuHjx4sDTp0+VhYUFPRqNbiWTSUPTNNHR0aG1t7d7uru7m0KhkLevr+9Qf3+/PxAI eHVd/2xtbe2fuq7/dWpqKuGUg04D50sFgkAwEokMvHjx4qimaa2qqrYoitIAsLOzs2UYRiqTySQz mcxKOp1e0HX9k+3t7SeV5Kcd1RL4QOp/GtofUQrANYgAAAAASUVORK5CYII= "
height="60"
width="60" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
Web/img/icons/icon32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
Web/img/icons/icon48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

BIN
Web/img/icons/icon60.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
Web/img/icons/icon64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
Web/img/icons/icon90.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

189
Web/index.html Normal file
View File

@ -0,0 +1,189 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset='UTF-8'>
<link rel='stylesheet/less' href='css/main.less'>
<link rel='stylesheet' href='css/switches.css'>
<link rel='stylesheet' href='css/value_selector.css'>
<link rel='stylesheet' href='css/seekbars.css'>
<link rel='stylesheet' href='css/color-picker.css'>
<script src='js/less-1.5.0.min.js'></script>
<script src='js/libs/mobilebrowsers.js'></script>
</head>
<body>
<header>
<button class='menu'></button>
<span class='separator long left menu'></span>
<p id='title'>Sketchy</p>
<button class='save'></button>
<span class='separator small right'></span>
</header>
<div id='container'>
<canvas></canvas>
<canvas></canvas>
</div>
<div id='menu'>
<p class='icon-settings'>Settings</p>
<div class='options'>
<div class='general'>
<button id='settype'>Brush Type<span>Sketch</span></button>
<button id='setcolor'>Color<span>#000000</span></button>
<!--<button id='setlineJoin'>Line Join<span>Round</span></button>-->
<button id='setlineCap'>Line Cap<span>Round</span></button>
<p id='lineWidth'>Line Width <span>2</span></p>
<div role="slider" class='lineWidth'>
<div>
<progress value="2" min="1" max="100"></progress>
<button style='left: 2%'>handler</button>
</div>
</div>
</div>
<br />
<hr>
<div class='sketch'>
<p class='icon-settings'>Sketch</p>
<p id='connectTelorance'>Connet Telorance<span>40</span></p>
<div role="slider" class='connectTelorance'>
<div>
<progress value="40" min="1" max="100"></progress>
<button style='left: 40%'>handler</button>
</div>
</div>
</div>
<div class='fur hidden'>
<p class='icon-settings'>Fur</p>
<p id='connectTelorance'>Connet Telorance<span>40</span></p>
<div role="slider" class='connectTelorance'>
<div>
<progress value="40" min="10" max="100"></progress>
<button style='left: 40%'>handler</button>
</div>
</div>
<p id='furLength'>Fur Length<span>20</span></p>
<div role="slider" class='furLength'>
<div>
<progress value="20" min="1" max="100"></progress>
<button style='left: 20%'>handler</button>
</div>
</div>
</div>
</div>
<div class='bottom'>
<button id='clear' class='icon-clear'>Clear</button>
<button id='undo' class='icon-undo'>Undo</button>
<button id='redo' class='icon-redo'>Redo</button>
<hr>
<button id='about'>About</button>
</div>
</div>
<form role='dialog' data-type='value-selector' id='type' class='hidden single'>
<section class='scrollable'>
<h1>Brush Type</h1>
<ol role='listbox'>
<li aria-selected='true'><label><span>Sketch</span></label></li>
<li><label><span>Fur</span></label></li>
<li><label><span>Pen</span></label></li>
<li><label><span>Line</span></label></li>
<!--<li><label><span>Eraser</span></label></li>-->
</ol>
</section>
<menu>
<button class='affirmative full'>Cancel</button>
</menu>
</form>
<form role='dialog' data-type='value-selector' id='lineJoin' class='hidden single'>
<section class='scrollable'>
<h1>Line Join</h1>
<ol role='listbox'>
<li aria-selected='true'><label><span>Round</span></label></li>
<li><label><span>Bevel</span></label></li>
<li><label><span>Miter</span></label></li>
</ol>
</section>
<menu>
<button class='affirmative full'>Cancel</button>
</menu>
</form>
<form role='dialog' data-type='value-selector' id='lineCap' class='hidden single'>
<section class='scrollable'>
<h1>Line Cap</h1>
<ol role='listbox'>
<li aria-selected='true'><label><span>Round</span></label></li>
<li><label><span>Square</span></label></li>
<li><label><span>Butt</span></label></li>
</ol>
</section>
<menu>
<button class='affirmative full'>Cancel</button>
</menu>
</form>
<form role='dialog' data-type='value-selector' id='save' class='hidden confirm'>
<section class='scrollable'>
<h1>Save</h1>
<h1>Background</h1>
<ol role='listbox'>
<li aria-selected='true'><label><span>White</span></label></li>
<li><label><span>Current Color</span></label></li>
<li><label><span>Transparent</span></label></li>
</ol>
<h1>File Name</h1>
<ol role='listbox'>
<li aria-selected='true' data-input><label><span contenteditable>My Sketch</span></label></li>
</ol>
</section>
<menu>
<button class='affirmative' type='button'>Cancel</button>
<button class='affirmative' type='button'>Save</button>
</menu>
</form>
<!-- COLOR PICKER -->
<div class='picker overlay hidden'>
<div class='color-picker'>
<input value='Hex' class='format' type='hidden' selected>
<input class='color' val='#000000'>
<div class="spectrum">
<div>
<div class="pin"></div>
</div>
</div>
<input class="luminosity" type="range" min="0" max="100" />
</div>
<button class='close'>x</button>
</div>
<div class='about overlay hidden'>
<p>Sketchy</p>
<span>Sketchy is a free sketch / paint application for Firefox OS.</span>
<p>Developer</p>
<span>Sketchy was found by Mahdi Dibaiee. More info: <a href='http://about.me/mdibaiee'>About.me</a>
<br><br>
Contact: <br>
<a href='https://twitter.com/mdibaiee'>Twitter</a><br />
<a href='mailto:mdibaiee@aol.com'>Email</a>
<br><br>
<a href='http://mdibaiee.github.io/Sketchy/changelog'>Changelog</a>
</span>
<button class='close'>x</button>
</div>
<script src='js/libs/yepnope.min.js'></script>
<script src='js/libs/zepto.min.js'></script>
<script src='js/functions.js'></script>
<script src='js/main.js'></script>
</body>
</html>

197
Web/js/desktop.js Normal file
View File

@ -0,0 +1,197 @@
"use strict";
$(window).resize(sizeAndPos);
// Check for update
function save() {
switch(save.background) {
case 'white': {
var cache = {
color: c.color,
composite: c.globalCompositeOperation
}
c.fillStyle = 'white';
c.globalCompositeOperation = 'destination-over';
c.fillRect(0, 0, width(), height());
c.fillStyle = cache.fillStyle;
c.globalCompositeOperation = cache.composite;
break;
}
case 'current color': {
var cache = {
fillStyle: c.color,
composite: c.globalCompositeOperation
}
c.fillStyle = settings.strokeStyle;
c.globalCompositeOperation = 'destination-over';
c.fillRect(0, 0, width(), height());
c.fillStyle = cache.fillStyle;
c.globalCompositeOperation = cache.composite;
break;
}
}
var data = $c[0].toDataURL();
window.open(data, save['file name']).focus();
c.putImageData(window.points.history[window.points.history.length-1].data, 0, 0);
}
$('.menu').click(function() {
$('#menu').toggleClass('pulled');
})
$('.save').click(function() {
$('#save').removeClass('hidden');
})
$c.last().on('mousedown', function(e) {
e.preventDefault();
var xy = relative(e.pageX, e.pageY);
startPoint(xy.x, xy.y);
window.active = true;
}).on('mousemove', function(e) {
e.preventDefault();
if (!window.active || settings.type == 'line') return;
var xy = relative(e.pageX, e.pageY);
drawPoint(xy.x, xy.y);
}).on('mouseup', function(e) {
e.preventDefault();
window.active = false;
if( settings.type == 'eraser' ) return;
if(window.points.history.last < window.points.history.length-1) {
window.points.history.splice(window.points.history.last+1);
}
window.points.history.push({
data: c.getImageData(0, 0, width(), height()),
points: window.points.slice(0)
})
window.points.history.last = window.points.history.length-1;
})
// Value Selector
// Single
var $single = $('form[data-type="value-selector"].single');
$single.find('li').click(function(e) {
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
var key = $(this).parents('form').attr('id'),
value = $(this).find('label span').html().toLowerCase();
window.settings[key] = value;
$('button[id="set' + key + '"] span').html(value[0].toUpperCase() + value.substr(1));
$('#menu div.options > div').addClass('hidden');
$('#menu div.options > .general, #menu div.options > .'+value).removeClass('hidden');
$(this).parents('form').addClass('hidden');
})
$single.submit(function(e) {
e.preventDefault();
$(this).addClass('hidden');
})
// Confirm
var $confirm = $('form[data-type="value-selector"].confirm');
$confirm.find('li').click(function(e) {
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
})
$confirm.find('button').last().click(function(e) {
e.preventDefault();
var v = $(this).parents('form').attr('id');
$(this).parents('form').find('h1').each(function(i) {
if( i > 0 ) {
var key = $(this).html().toLowerCase();
var value = $(this).parent().find('ol:nth-of-type('+i+') li[aria-selected] span').html();
if( key !== 'file name' ) value = key.toLowerCase();
window[v][key] = value;
}
})
$(this).parents('form').addClass('hidden');
window[v]();
})
$confirm.find('button').first().click(function(e) {
e.preventDefault();
$(this).parents('form').addClass('hidden');
})
// Value Selector Callers
var $btn = $('button[id^="set"]');
$btn.each(function() {
var target = /set(.*)/.exec($(this).attr('id'))[1];
// Exception for Color
if( target == 'color' ) {
return $(this).click(function() {
$('.picker').removeClass('hidden');
})
}
$(this).click(function(e) {
e.preventDefault();
$('form[id="' + target + '"]').removeClass('hidden');
})
})
// Seekbar
var sliderLeft;
$('div[role="slider"] button').on('mousedown', function() {
$(this).attr('data-moving','true');
if( !sliderLeft ) sliderLeft = $('div[role="slider"] button').offset().left;
}).on('mousemove', function(e) {
if( $(this).attr('data-moving') ) {
var x = parseInt(e.pageX - sliderLeft - 15);
var $c = $('.'+$(this).parents('div[role="slider"]').attr('class'));
var progress = $c.find('progress');
var max = +progress.attr('max');
var min = +progress.attr('min');
if( x <= max && x >= min ) {
$c.find('button').css('left', x+'%');
progress.attr('value', x);
var key = $c.attr('class');
settings[key] = x;
$('#'+ key +' span').html(x);
}
}
}).on('mouseup mouseleave', function() {
$(this).removeAttr('data-moving');
})
// Color Picker
$('.close').click(function() {
$(this).parent().addClass('hidden');
})
// Bottom
$('#clear').click(function() {
c.clearRect(0, 0, width(), height());
window.points = [];
if(window.points.history.last < window.points.history.length-1) {
window.points.history.splice(window.points.history.last+1);
}
window.points.history.push({
data: c.getImageData(0, 0, width(), height()),
points: []
})
window.points.history.last = window.points.history.length-1;
})
$('#undo').click(undo);
$('#redo').click(redo);
$('#about').click(function() {
$('.about').removeClass('hidden');
})

196
Web/js/functions.js Normal file
View File

@ -0,0 +1,196 @@
"use strict";
/*** ESSENTIALS ***/
function sizeAndPos() {
var data = window.points.history[window.points.history.last].data || c.getImageData(0,0, $c.width(), $c.height());
var w = $(window).width(),
h = $(window).height() - 53;
$c.attr('width', w * window.devicePixelRatio);
$c.attr('height',h * window.devicePixelRatio);
$c.css({
'width' : w,
'height' : h
});
c.clearRect(0,0, width(), height());
c.putImageData(data, 0, 0);
}
function relative(x,y) {
return {
x : x*window.devicePixelRatio,
y : (y - 53) * window.devicePixelRatio
}
}
function threshold(x1, y1, x2, y2, threshold) {
var tr = threshold || 5;
if( x1 <= x2 + tr && x1 >= x2 - tr && y1 <= y2 + tr && y1 >= y2 - tr ) return true;
return false;
}
function draw(x1, y1, x2, y2, opts, overlay) {
opts = opts || {};
var c = window.c;
if( overlay ) var c = window.o;
c.beginPath();
if( settings.type == 'eraser' ) c.globalCompositeOperation = 'destination-out';
else c.globalCompositeOperation = opts.composite || settings.composite;
c.lineCap = opts.lineCap || settings.lineCap;
c.lineJoin = opts.lineJoin || settings.lineJoin;
c.strokeStyle = opts.color || settings.color;
c.fillStyle = opts.color || settings.color;
c.lineWidth = ( opts.lineWidth || settings.lineWidth ) / 10;
c.moveTo(x1, y1);
c.lineTo(x2, y2);
if( !opts.noStroke ) c.stroke();
if( opts.fill ) c.fill();
}
function undo() {
var history = window.points.history;
if( history.last > 1 ) {
var step = history[history.last-1];
c.putImageData(step.data, 0, 0);
window.points = step.points.slice(0);
window.points.history = history;
window.points.history.last = history.last-1;
} else {
c.clearRect(0,0, width(), height());
window.points = [];
window.points.history = history;
window.points.history.last = 0;
}
}
function redo() {
var history = window.points.history;
if( history.last < history.length-1 ) {
var step = history[history.last+1];
c.putImageData(step.data, 0, 0);
window.points = step.points.slice(0);
window.points.history = history;
window.points.history.last = history.last+1;
}
}
function width() {
return +$c.attr('width');
}
function height() {
return +$c.attr('height');
}
function dataToBlob(data) {
var binary = atob(data.split(',')[1]), array = [];
var type = data.split(',')[0].split(':')[1].split(';')[0];
for(var i = 0; i < binary.length; i++) array.push(binary.charCodeAt(i));
return new Blob([new Uint8Array(array)], {type: type});
}
/*** END ***/
function startPoint(x, y) {
// If no previous point exists, make the first one.
if( !points.length ) points.push({x: x, y: y, type: '', start: {x: x, y: y}});
var old = points[points.length-1],
start = old.start,
current = {
x : x,
y : y,
start : old.start || {x: x, y: y},
type : settings.type
}
if( old.type !== 'line' && current.type == 'line' ) {
window.o.beginPath();
window.o.fillStyle = 'red';
window.o.arc(x,y, 3, 0, 2*Math.PI);
window.o.fill();
}
if( old.type == 'line' && current.type == 'line' ) {
if( points[points.indexOf(old)-1].type !== 'line' ) {
o.clearRect(old.x-3, old.y-3, 6, 6, true);
draw(old.x, old.y, x, y);
} else
draw(old.x, old.y, x, y);
}
var thresholds = window.mobile ? [10, 5] : [5, 2];
if( points.length > 1 && ((start && threshold(start.x, start.y, x, y, thresholds[0])) || threshold(old.x, old.y, x, y, thresholds[1])) ) {
window.active = false;
points[points.length-1].type = '';
points[points.length-1].start = undefined;
return;
}
points.push(current);
}
function drawPoint(x,y) {
var capture = points[points.length-1];
switch(capture.type) {
case 'eraser': {
capture.type = 'pen';
}
case 'pen': {
draw(capture.x, capture.y, x, y);
var current = {
x : x,
y : y,
start : capture.start,
type : capture.type
}
points.push(current);
break;
}
case 'sketch': {
draw(capture.x, capture.y, x, y);
var current = {
x : x,
y : y,
start : capture.start,
type : capture.type
}
points.push(current);
for( var i = 0, len = points.length-1; i < len; i++ ) {
if(threshold(points[i].x, points[i].y, current.x, current.y, settings.connectTelorance)) {
var x = points[i].x - current.x,
y = points[i].y - current.y;
draw(points[i].x - x*0.2, points[i].y - y*0.2, current.x + x*0.2, current.y + y*0.2, {strokeStyle: 'rgba(0,0,0,0.4)', lineWidth: settings.lineWidth/20})
}
}
break;
}
case 'fur': {
draw(capture.x, capture.y, x, y);
var current = {
x : x,
y : y,
start : capture.start,
type : capture.type
}
points.push(current);
for( var i = 0, len = points.length-1; i < len; i++ ) {
if(threshold(points[i].x, points[i].y, current.x, current.y, settings.connectTelorance)) {
var x = points[i].x - current.x,
y = points[i].y - current.y;
var l = settings.furLength / 100 || 0.2;
draw(points[i].x + x*l, points[i].y + y*l, current.x - x*l, current.y - y*l, {strokeStyle: 'rgba(0,0,0,0.4)', lineWidth: settings.lineWidth/2})
}
}
break;
}
}
}

13
Web/js/less-1.5.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,290 @@
/*
Purty Picker Copyright 2013 Jayden Seric (MIT license).
A super lightweight visual HSL, RGB and hex color picker with a responsive, touch-friendly and customizable UI.
Requires jQuery or Zepto with core and event modules.
https://github.com/jaydenseric/Purty-Picker
*/
// DOM ready
$(function() {
'use strict';
//-------------------------------------------- Color conversions
//---------------------- Convert HSL to RGB
// Source: http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function HSLToRGB(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
var r, g, b;
if(s == 0) {
r = g = b = l; // Achromatic
} else {
var hueToRGB = function(p, q, t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
p = 2 * l - q;
r = hueToRGB(p, q, h + 1/3);
g = hueToRGB(p, q, h);
b = hueToRGB(p, q, h - 1/3);
}
return {
red: Math.round(r * 255),
green: Math.round(g * 255),
blue: Math.round(b * 255)
};
}
//---------------------- Convert RGB to HSL
// Source: http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function RGBToHSL(r, g, b) {
r /= 255,
g /= 255,
b /= 255;
var max = Math.max(r, g, b),
min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // Achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return {
hue: Math.round(h * 360),
saturation: Math.round(s * 100),
luminosity: Math.round(l * 100)
};
}
//---------------------- Convert RGB to Hex
// Source: http://stackoverflow.com/a/5624139
function RGBToHex(r, g, b) {
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
//---------------------- Convert hex to RGB
// Source: http://stackoverflow.com/a/11508164
function hexToRGB(hex) {
var bigInt = parseInt(hex.replace('#', ''), 16),
r = (bigInt >> 16) & 255,
g = (bigInt >> 8) & 255,
b = bigInt & 255;
return {
red: r,
green: g,
blue: b
};
}
//---------------------- Convert hex to HSL
function hexToHSL(hex) {
var RGB = hexToRGB(hex);
return RGBToHSL(RGB.red, RGB.green, RGB.blue);
}
//---------------------- Convert HSL to hex
function HSLToHex(h, s, l) {
var RGB = HSLToRGB(h, s, l);
return RGBToHex(RGB.red, RGB.green, RGB.blue);
}
//-------------------------------------------- Setup each color picker
$.each($('.color-picker'), function() {
//---------------------- Find componenets
var picker = $(this),
formatInput = picker.find('.format'),
colorInput = picker.find('.color'),
luminosityInput = picker.find('input[type=range]'),
spectrum = picker.find('.spectrum'),
pin = picker.find('.pin');
//---------------------- Get current color in HSL
function getHSL() {
var position = picker.find('.pin').position(),
width = spectrum.width(),
height = spectrum.height();
return {
hue: Math.round(position.left / width * 360),
saturation: Math.round(position.top / height * 100),
luminosity: luminosityInput.val()
};
}
//---------------------- Output color in desired format
function updateColorInput() {
var HSL = getHSL();
switch (formatInput.val()) {
case 'HSL':
colorInput.val('hsl(' + HSL.hue + ', ' + HSL.saturation + '%, ' + HSL.luminosity + '%)');
break;
case 'RGB':
var RGB = HSLToRGB(HSL.hue, HSL.saturation, HSL.luminosity);
colorInput.val('rgb(' + RGB.red + ', ' + RGB.green + ', ' + RGB.blue + ')');
break;
case 'Hex':
colorInput.val(HSLToHex(HSL.hue, HSL.saturation, HSL.luminosity));
break;
}
// Trigger color picker change event for custom callbacks
picker.trigger('change');
}
//---------------------- Set color format
formatInput.on('change', function() {
updateColorInput();
});
//---------------------- Set color
colorInput.on('change', function() {
// Get the color values in HSL format
var HSL;
switch (formatInput.val()) {
case 'HSL':
var values = $(this).val().match(/\d+/g);
HSL = {
hue: values[0],
saturation: values[1],
luminosity: values[2]
};
break;
case 'RGB':
var values = $(this).val().match(/\d+/g);
HSL = RGBToHSL(values[0], values[1], values[2]);
break;
case 'Hex':
HSL = hexToHSL($(this).val());
break;
}
// Set the luminosity
luminosityInput.val(HSL.luminosity);
setLuminosity(HSL.luminosity);
// Place the pin
pin.css({
left: HSL.hue / 360 * 100 + '%',
top: HSL.saturation + '%'
});
// Trigger color picker change event for custom callbacks
picker.trigger('change');
});
//---------------------- Set luminosity
//---------- Set the luminosity spectrum overlay
function setLuminosity(luminosity) {
var color,
alpha;
if (luminosity <= 50) {
color = '0, 0, 0';
alpha = 1 - luminosity / 100 * 2;
} else {
color = '255, 255, 255';
alpha = luminosity / 100 * 2 - 1;
}
// Apply luminosity to the spectrum
spectrum.children().css('background-color', 'rgba(' + color + ', ' + alpha + ')');
}
//---------- Luminosity input interaction
luminosityInput.on('change', function() {
setLuminosity($(this).val());
updateColorInput();
});
//---------------------- Set hue, saturation via pin
//---------- Move the pin
var movePin = function(event) {
var offset = spectrum.offset(),
width = spectrum.width(),
height = spectrum.height(),
x = event.changedTouches[0].clientX - offset.left,
y = event.changedTouches[0].clientY - offset.top;
// Account for pin being dragged outside the spectrum area
// Sanatize x
if (x < 0) {
x = 0;
} else if (x >= width) {
x = width;
}
// Sanatize y
if (y < 0) {
y = 0;
} else if (y >= height) {
y = height;
}
// Place the pin
pin.css({
left: x / width * 100 + '%',
top: y / height * 100 + '%'
});
// Output new color value
updateColorInput();
};
//---------- Pin interaction
spectrum.on('touchstart', function(event) {
event.preventDefault();
movePin(event);
spectrum.addClass('active');
$(document).on('touchmove', movePin);
});
$(document).on('touchend', function() {
spectrum.removeClass('active');
$(document).off('touchmove', movePin);
});
spectrum.on('touchmove touchstart', movePin);
//---------------------- Output color preview
picker.on('change', function() {
colorInput.css('background-color', colorInput.val()).toggleClass('dark', luminosityInput.val() <= 50);
});
//---------------------- Initialize this color picker
colorInput.trigger('change');
});
});

289
Web/js/libs/color-picker.js Normal file
View File

@ -0,0 +1,289 @@
/*
Purty Picker Copyright 2013 Jayden Seric (MIT license).
A super lightweight visual HSL, RGB and hex color picker with a responsive, touch-friendly and customizable UI.
Requires jQuery or Zepto with core and event modules.
https://github.com/jaydenseric/Purty-Picker
*/
// DOM ready
$(function() {
'use strict';
//-------------------------------------------- Color conversions
//---------------------- Convert HSL to RGB
// Source: http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function HSLToRGB(h, s, l) {
h /= 360;
s /= 100;
l /= 100;
var r, g, b;
if(s == 0) {
r = g = b = l; // Achromatic
} else {
var hueToRGB = function(p, q, t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
var q = l < 0.5 ? l * (1 + s) : l + s - l * s,
p = 2 * l - q;
r = hueToRGB(p, q, h + 1/3);
g = hueToRGB(p, q, h);
b = hueToRGB(p, q, h - 1/3);
}
return {
red: Math.round(r * 255),
green: Math.round(g * 255),
blue: Math.round(b * 255)
};
}
//---------------------- Convert RGB to HSL
// Source: http://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
function RGBToHSL(r, g, b) {
r /= 255,
g /= 255,
b /= 255;
var max = Math.max(r, g, b),
min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // Achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return {
hue: Math.round(h * 360),
saturation: Math.round(s * 100),
luminosity: Math.round(l * 100)
};
}
//---------------------- Convert RGB to Hex
// Source: http://stackoverflow.com/a/5624139
function RGBToHex(r, g, b) {
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
//---------------------- Convert hex to RGB
// Source: http://stackoverflow.com/a/11508164
function hexToRGB(hex) {
var bigInt = parseInt(hex.replace('#', ''), 16),
r = (bigInt >> 16) & 255,
g = (bigInt >> 8) & 255,
b = bigInt & 255;
return {
red: r,
green: g,
blue: b
};
}
//---------------------- Convert hex to HSL
function hexToHSL(hex) {
var RGB = hexToRGB(hex);
return RGBToHSL(RGB.red, RGB.green, RGB.blue);
}
//---------------------- Convert HSL to hex
function HSLToHex(h, s, l) {
var RGB = HSLToRGB(h, s, l);
return RGBToHex(RGB.red, RGB.green, RGB.blue);
}
//-------------------------------------------- Setup each color picker
$.each($('.color-picker'), function() {
//---------------------- Find componenets
var picker = $(this),
formatInput = picker.find('.format'),
colorInput = picker.find('.color'),
luminosityInput = picker.find('input[type=range]'),
spectrum = picker.find('.spectrum'),
pin = picker.find('.pin');
//---------------------- Get current color in HSL
function getHSL() {
var position = picker.find('.pin').position(),
width = spectrum.width(),
height = spectrum.height();
return {
hue: Math.round(position.left / width * 360),
saturation: Math.round(position.top / height * 100),
luminosity: luminosityInput.val()
};
}
//---------------------- Output color in desired format
function updateColorInput() {
var HSL = getHSL();
switch (formatInput.val()) {
case 'HSL':
colorInput.val('hsl(' + HSL.hue + ', ' + HSL.saturation + '%, ' + HSL.luminosity + '%)');
break;
case 'RGB':
var RGB = HSLToRGB(HSL.hue, HSL.saturation, HSL.luminosity);
colorInput.val('rgb(' + RGB.red + ', ' + RGB.green + ', ' + RGB.blue + ')');
break;
case 'Hex':
colorInput.val(HSLToHex(HSL.hue, HSL.saturation, HSL.luminosity));
break;
}
// Trigger color picker change event for custom callbacks
picker.trigger('change');
}
//---------------------- Set color format
formatInput.on('change', function() {
updateColorInput();
});
//---------------------- Set color
colorInput.on('change', function() {
// Get the color values in HSL format
var HSL;
switch (formatInput.val()) {
case 'HSL':
var values = $(this).val().match(/\d+/g);
HSL = {
hue: values[0],
saturation: values[1],
luminosity: values[2]
};
break;
case 'RGB':
var values = $(this).val().match(/\d+/g);
HSL = RGBToHSL(values[0], values[1], values[2]);
break;
case 'Hex':
HSL = hexToHSL($(this).val());
break;
}
// Set the luminosity
luminosityInput.val(HSL.luminosity);
setLuminosity(HSL.luminosity);
// Place the pin
pin.css({
left: HSL.hue / 360 * 100 + '%',
top: HSL.saturation + '%'
});
// Trigger color picker change event for custom callbacks
picker.trigger('change');
});
//---------------------- Set luminosity
//---------- Set the luminosity spectrum overlay
function setLuminosity(luminosity) {
var color,
alpha;
if (luminosity <= 50) {
color = '0, 0, 0';
alpha = 1 - luminosity / 100 * 2;
} else {
color = '255, 255, 255';
alpha = luminosity / 100 * 2 - 1;
}
// Apply luminosity to the spectrum
spectrum.children().css('background-color', 'rgba(' + color + ', ' + alpha + ')');
}
//---------- Luminosity input interaction
luminosityInput.on('change', function() {
setLuminosity($(this).val());
updateColorInput();
});
//---------------------- Set hue, saturation via pin
//---------- Move the pin
var movePin = function(event) {
var offset = spectrum.offset(),
width = spectrum.width(),
height = spectrum.height(),
x = event.clientX - offset.left,
y = event.clientY - offset.top;
// Account for pin being dragged outside the spectrum area
// Sanatize x
if (x < 0) {
x = 0;
} else if (x >= width) {
x = width;
}
// Sanatize y
if (y < 0) {
y = 0;
} else if (y >= height) {
y = height;
}
// Place the pin
pin.css({
left: x / width * 100 + '%',
top: y / height * 100 + '%'
});
// Output new color value
updateColorInput();
};
//---------- Pin interaction
spectrum.on('mousedown', function(event) {
event.preventDefault();
movePin(event);
spectrum.addClass('active');
$(document).on('mousemove', movePin);
});
$(document).on('mouseup', function() {
spectrum.removeClass('active');
$(document).off('mousemove', movePin);
});
spectrum.on('touchmove touchstart', movePin);
//---------------------- Output color preview
picker.on('change', function() {
colorInput.css('background-color', colorInput.val()).toggleClass('dark', luminosityInput.val() <= 50);
});
//---------------------- Initialize this color picker
colorInput.trigger('change');
});
});

View File

@ -0,0 +1 @@
(function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))window.mobile=true})(navigator.userAgent||navigator.vendor||window.opera,'http://detectmobilebrowser.com/mobile');

22
Web/js/libs/stack.js Normal file
View File

@ -0,0 +1,22 @@
// Zepto.js
// (c) 2010-2014 Thomas Fuchs
// Zepto.js may be freely distributed under the MIT license.
;(function($){
$.fn.end = function(){
return this.prevObject || $()
}
$.fn.andSelf = function(){
return this.add(this.prevObject || $())
}
'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function(property){
var fn = $.fn[property]
$.fn[property] = function(){
var ret = fn.apply(this, arguments)
ret.prevObject = this
return ret
}
})
})(Zepto)

166
Web/js/libs/touch.js Normal file
View File

@ -0,0 +1,166 @@
// Zepto.js
// (c) 2010-2014 Thomas Fuchs
// Zepto.js may be freely distributed under the MIT license.
;(function($){
var touch = {},
touchTimeout, tapTimeout, swipeTimeout, longTapTimeout,
longTapDelay = 750,
gesture
function swipeDirection(x1, x2, y1, y2) {
return Math.abs(x1 - x2) >=
Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
}
function longTap() {
longTapTimeout = null
if (touch.last) {
touch.el.trigger('longTap')
window.touchEl = touch.el;
touch = {}
}
}
function cancelLongTap() {
if (longTapTimeout) clearTimeout(longTapTimeout)
longTapTimeout = null
}
function cancelAll() {
if (touchTimeout) clearTimeout(touchTimeout)
if (tapTimeout) clearTimeout(tapTimeout)
if (swipeTimeout) clearTimeout(swipeTimeout)
if (longTapTimeout) clearTimeout(longTapTimeout)
touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null
touch = {}
}
function isPrimaryTouch(event){
return (event.pointerType == 'touch' ||
event.pointerType == event.MSPOINTER_TYPE_TOUCH)
&& event.isPrimary
}
function isPointerEventType(e, type){
return (e.type == 'pointer'+type ||
e.type.toLowerCase() == 'mspointer'+type)
}
$(document).ready(function(){
var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType
if ('MSGesture' in window) {
gesture = new MSGesture()
gesture.target = document.body
}
$(document)
.bind('MSGestureEnd', function(e){
var swipeDirectionFromVelocity =
e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null;
if (swipeDirectionFromVelocity) {
touch.el.trigger('swipe')
touch.el.trigger('swipe'+ swipeDirectionFromVelocity)
}
})
.on('touchstart MSPointerDown pointerdown', function(e){
if((_isPointerType = isPointerEventType(e, 'down')) &&
!isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]
if (e.touches && e.touches.length === 1 && touch.x2) {
// Clear out touch movement data if we have it sticking around
// This can occur if touchcancel doesn't fire due to preventDefault, etc.
touch.x2 = undefined
touch.y2 = undefined
}
now = Date.now()
delta = now - (touch.last || now)
touch.el = $('tagName' in firstTouch.target ?
firstTouch.target : firstTouch.target.parentNode)
touchTimeout && clearTimeout(touchTimeout)
touch.x1 = firstTouch.pageX
touch.y1 = firstTouch.pageY
if (delta > 0 && delta <= 250) touch.isDoubleTap = true
touch.last = now
longTapTimeout = setTimeout(longTap, longTapDelay)
// adds the current touch contact for IE gesture recognition
if (gesture && _isPointerType) gesture.addPointer(e.pointerId);
})
.on('touchmove MSPointerMove pointermove', function(e){
if((_isPointerType = isPointerEventType(e, 'move')) &&
!isPrimaryTouch(e)) return
firstTouch = _isPointerType ? e : e.touches[0]
if( $.moveCancel ) cancelLongTap()
touch.x2 = firstTouch.pageX
touch.y2 = firstTouch.pageY
deltaX += Math.abs(touch.x1 - touch.x2)
deltaY += Math.abs(touch.y1 - touch.y2)
})
.on('touchend MSPointerUp pointerup', function(e){
if((_isPointerType = isPointerEventType(e, 'up')) &&
!isPrimaryTouch(e)) return
cancelLongTap()
// swipe
if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
(touch.y2 && Math.abs(touch.y1 - touch.y2) > 30))
swipeTimeout = setTimeout(function() {
touch.el.trigger('swipe')
touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
touch = {}
}, 0)
// normal tap
else if ('last' in touch)
// don't fire tap when delta position changed by more than 30 pixels,
// for instance when moving to a point and back to origin
if (deltaX < 30 && deltaY < 30) {
// delay by one tick so we can cancel the 'tap' event if 'scroll' fires
// ('tap' fires before 'scroll')
tapTimeout = setTimeout(function() {
// trigger universal 'tap' with the option to cancelTouch()
// (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
var event = $.Event('tap')
event.cancelTouch = cancelAll
touch.el.trigger(event)
// trigger double tap immediately
if (touch.isDoubleTap) {
if (touch.el) touch.el.trigger('doubleTap')
touch = {}
}
// trigger single tap after 250ms of inactivity
else {
touchTimeout = setTimeout(function(){
touchTimeout = null
if (touch.el) touch.el.trigger('singleTap')
touch = {}
}, 250)
}
}, 0)
} else {
touch = {}
}
deltaX = deltaY = 0
})
// when the browser window loses focus,
// for example when a modal dialog is shown,
// cancel all ongoing events
.on('touchcancel MSPointerCancel pointercancel', cancelAll)
// scrolling the window indicates intention of the user
// to scroll, not tap or swipe, so cancel all ongoing events
$(window).on('scroll', cancelAll)
})
;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown',
'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){
$.fn[eventName] = function(callback){ return this.on(eventName, callback) }
})
})(Zepto)

2
Web/js/libs/yepnope.min.js vendored Normal file
View File

@ -0,0 +1,2 @@
/*yepnope1.5.x|WTFPL*/
(function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f<d;f++)g=a[f].split("="),(e=z[g.shift()])&&(c=e(c,g));for(f=0;f<b;f++)c=x[f](c);return c}function g(a,e,f,g,h){var i=b(a),j=i.autoCallback;i.url.split(".").pop().split("?").shift(),i.bypass||(e&&(e=d(e)?e:e[a]||e[g]||e[a.split("/").pop().split("?")[0]]),i.instead?i.instead(a,e,f,g,h):(y[i.url]?i.noexec=!0:y[i.url]=1,f.load(i.url,i.forceCSS||!i.forceJS&&"css"==i.url.split(".").pop().split("?").shift()?"c":c,i.noexec,i.attrs,i.timeout),(d(e)||d(j))&&f.load(function(){k(),e&&e(i.origUrl,h,g),j&&j(i.origUrl,h,g),y[i.url]=2})))}function h(a,b){function c(a,c){if(a){if(e(a))c||(j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}),g(a,j,b,0,h);else if(Object(a)===a)for(n in m=function(){var b=0,c;for(c in a)a.hasOwnProperty(c)&&b++;return b}(),a)a.hasOwnProperty(n)&&(!c&&!--m&&(d(j)?j=function(){var a=[].slice.call(arguments);k.apply(this,a),l()}:j[n]=function(a){return function(){var b=[].slice.call(arguments);a&&a.apply(this,b),l()}}(k[n])),g(a[n],j,b,n,h))}else!c&&l()}var h=!!a.test,i=a.load||a.both,j=a.callback||f,k=j,l=a.complete||f,m,n;c(h?a.yep:a.nope,!!i),i&&c(i)}var i,j,l=this.yepnope.loader;if(e(a))g(a,0,l,0);else if(w(a))for(i=0;i<a.length;i++)j=a[i],e(j)?g(j,0,l,0):w(j)?B(j):Object(j)===j&&h(j,l);else Object(a)===a&&h(a,l)},B.addPrefix=function(a,b){z[a]=b},B.addFilter=function(a){x.push(a)},B.errorTimeout=1e4,null==b.readyState&&b.addEventListener&&(b.readyState="loading",b.addEventListener("DOMContentLoaded",A=function(){b.removeEventListener("DOMContentLoaded",A,0),b.readyState="complete"},0)),a.yepnope=k(),a.yepnope.executeStack=h,a.yepnope.injectJs=function(a,c,d,e,i,j){var k=b.createElement("script"),l,o,e=e||B.errorTimeout;k.src=a;for(o in d)k.setAttribute(o,d[o]);c=j?h:c||f,k.onreadystatechange=k.onload=function(){!l&&g(k.readyState)&&(l=1,c(),k.onload=k.onreadystatechange=null)},m(function(){l||(l=1,c(1))},e),i?k.onload():n.parentNode.insertBefore(k,n)},a.yepnope.injectCss=function(a,c,d,e,g,i){var e=b.createElement("link"),j,c=i?h:c||f;e.href=a,e.rel="stylesheet",e.type="text/css";for(j in d)e.setAttribute(j,d[j]);g||(n.parentNode.insertBefore(e,n),m(c,0))}})(this,document);

2
Web/js/libs/zepto.min.js vendored Normal file

File diff suppressed because one or more lines are too long

38
Web/js/main.js Normal file
View File

@ -0,0 +1,38 @@
"use strict";
$(document).ready(function() {
window.c = $('canvas')[0].getContext('2d');
window.o = $('canvas')[1].getContext('2d');
window.settings = {
lineWidth : 2,
color : 'black',
type: 'sketch',
lineCap: 'round',
lineJoin: 'round',
furLength: 5,
connectTelorance: 40,
composite: 'source-over'
};
window.points = [];
window.$c = $('canvas');
window.points.history = [{ data: c.createImageData($c.width(), $c.height()), points: []}];
window.points.history.last = 0;
sizeAndPos();
//$(window).resize(sizeAndPos);
$('.color-picker').change(function() {
var c = $(this).find('.color').val();
settings.color = c;
$('#setcolor span').html(c);
})
$('.color').val('#000000');
yepnope({
test: window.mobile,
yep : ['js/libs/touch.js', 'js/mobile.js', 'js/libs/color-picker-touch.js'],
nope: ['js/desktop.js', 'js/libs/color-picker.js']
})
})

223
Web/js/mobile.js Normal file
View File

@ -0,0 +1,223 @@
"use strict";
$(document).ready(function() {
// Open External Links in browser
$('*').click(function(e) {
e.preventDefault();
})
$('a[href^="http"]').on('tap', function(e) {
e.preventDefault();
var href = $(this).attr('href');
var view = new MozActivity({
name: 'view',
data: {
type: 'url',
url: href
}
})
})
function save() {
switch(save.background) {
case 'white': {
var cache = {
fillStyle: c.color,
composite: c.globalCompositeOperation
}
c.fillStyle = 'white';
c.globalCompositeOperation = 'destination-over';
c.fillRect(0, 0, width(), height());
c.fillStyle = cache.fillStyle;
c.globalCompositeOperation = cache.composite;
break;
}
case 'current color': {
var cache = {
fillStyle: c.color,
composite: c.globalCompositeOperation
}
c.fillStyle = settings.strokeStyle;
c.globalCompositeOperation = 'destination-over';
c.fillRect(0, 0, width(), height());
c.fillStyle = cache.fillStyle;
c.globalCompositeOperation = cache.composite;
break;
}
}
var data = $c[0].toDataURL();
var file = dataToBlob($c[0].toDataURL());
var pics = navigator.getDeviceStorage('pictures');
var r = pics.addNamed(file, save['file name'] + '.png');
r.onsuccess = function() {
alert('Your sketch was successfuly saved to ' + this.result);
}
r.onerror = function() {
alert('Something bad happened when we tried to save your file\n Possible problems: \n Duplicate name \n Permission problems')
console.warn(this.error);
}
c.putImageData(window.points.history[window.points.history.last].data, 0, 0);
}
$('.menu').tap(function() {
$('#menu').toggleClass('pulled');
})
$('.save').tap(function() {
$('#save').removeClass('hidden');
})
$c.last().on('touchstart', function(e) {
var xy = relative(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
startPoint(xy.x, xy.y);
window.active = true;
}).on('touchmove', function(e) {
if (!window.active || settings.type == 'line') return;
var xy = relative(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
drawPoint(xy.x, xy.y);
}).on('touchend', function(e) {
window.active = false;
if( settings.type == 'eraser' ) return;
if(window.points.history.last < window.points.history.length-1) {
window.points.history.splice(window.points.history.last+1);
}
window.points.history.push({
data: c.getImageData(0, 0, width(), height()),
points: window.points.slice(0)
})
window.points.history.last = window.points.history.length-1;
}).on('longTap', function(e) {
if( points[points.length-1].type == 'line' ) {
window.active = false;
points[points.length-1].type = '';
points[points.length-1].start = undefined;
}
})
// Value Selector
var $single = $('form[data-type="value-selector"].single');
$single.find('li').tap(function(e) {
e.preventDefault();
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
var key = $(this).parents('form').attr('id'),
value = $(this).find('label span').html().toLowerCase();
window.settings[key] = value;
$('button[id="set' + key + '"] span').html(value[0].toUpperCase() + value.substr(1));
$('#menu div.options > div').addClass('hidden');
$('#menu div.options > .general, #menu div.options > .'+value).removeClass('hidden');
$(this).parents('form').addClass('hidden');
})
$single.submit(function(e) {
e.preventDefault();
$(this).addClass('hidden');
})
// Confirm
var $confirm = $('form[data-type="value-selector"].confirm');
$confirm.find('li').tap(function(e) {
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
})
$confirm.find('button').last().tap(function(e) {
e.preventDefault();
var v = $(this).parents('form').attr('id');
$(this).parents('form').find('h1').each(function(i) {
if( i > 0 ) {
var key = $(this).html().toLowerCase();
var value = $(this).parent().find('ol:nth-of-type('+i+') li[aria-selected] span').html();
if( key !== 'file name' ) value = value.toLowerCase();
window[v][key] = value;
}
})
$(this).parents('form').addClass('hidden');
window[v]();
})
$confirm.find('button').first().tap(function(e) {
e.preventDefault();
$(this).parents('form').addClass('hidden');
})
// Value Selector Callers
var $btn = $('button[id^="set"]');
$btn.each(function() {
var target = /set(.*)/.exec($(this).attr('id'))[1];
if( target == 'color' ) {
return $(this).tap(function() {
$('.picker').removeClass('hidden');
})
}
$(this).tap(function(e) {
e.preventDefault();
$('form[id="' + target + '"]').removeClass('hidden');
})
})
// Seekbar
var sliderLeft;
$('div[role="slider"] button').on('touchstart', function() {
$(this).attr('data-moving','true');
if( !sliderLeft ) sliderLeft = $('div[role="slider"] button').offset().left;
}).on('touchmove', function(e) {
if( $(this).attr('data-moving') ) {
var x = parseInt(e.changedTouches[0].pageX - sliderLeft - 15);
var $c = $('.'+$(this).parents('div[role="slider"]').attr('class'));
var progress = $c.find('progress');
var max = +progress.attr('max');
var min = +progress.attr('min');
if( x <= max && x >= min ) {
$c.find('button').css('left', x+'%');
progress.attr('value', x);
var key = $c.attr('class');
settings[key] = x;
$('#'+ key +' span').html(x);
}
}
}).on('touchend', function() {
$(this).removeAttr('data-moving');
})
// Color Picker
$('.close').tap(function() {
$(this).parent().addClass('hidden');
})
// Bottom
$('#clear').tap(function() {
c.clearRect(0, 0, width(), height());
var h = window.points.history;
window.points = [];
window.points.history = h;
if(window.points.history.last < window.points.history.length-1) {
window.points.history.splice(window.points.history.last+1);
}
window.points.history.push({
data: c.getImageData(0, 0, width(), height()),
points: []
})
window.points.history.last = window.points.history.length-1;
})
$('#undo').tap(undo);
$('#redo').tap(redo);
$('#about').tap(function() {
$('.about').removeClass('hidden');
})
});

31
Web/manifest-web.webapp Normal file
View File

@ -0,0 +1,31 @@
{
"name": "Sketchy Web",
"description": "Free Sketch/Paint app",
"version": "1",
"default_locale": "en",
"launch_path": "/Sketchy/index.html",
"icons": {
"16": "/Sketchy/img/icons/icon16.png",
"32": "/Sketchy/img/icons/icon32.png",
"48": "/Sketchy/img/icons/icon48.png",
"60": "/Sketchy/img/icons/icon60.png",
"64": "/Sketchy/img/icons/icon64.png",
"90": "/Sketchy/img/icons/icon90.png",
"120": "/Sketchy/img/icons/icon120.png",
"128": "/Sketchy/img/icons/icon128.png"
},
"developer": {
"name": "Mahdi Dibaiee",
"url": "https://twitter.com/mdibaiee"
},
"locales": {
"en": {
"name": "Sketchy Web",
"description": "Free Sketch/Paint app"
},
"fa": {
"name": "Sketchy Web",
"description": "برنامه‌ی رایگان طراحی/نقاشی"
}
}
}