@@ -181,13 +196,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Mobile/js/mobile.js b/Mobile/js/mobile.js
index 0af6f31..9200b6c 100644
--- a/Mobile/js/mobile.js
+++ b/Mobile/js/mobile.js
@@ -51,17 +51,39 @@ window.save = function() {
}
}
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')
+ if( save.type == 'sketchy project' ) {
+ if( localStorage.getItem(save['file name']) ) {
+ if( confirm('A sketch with this name already exists. Do you want to overwrite ' + save['file name']) + '?' ) {
+ localStorage.setItem(save['file name'], JSON.stringify({data: data, points: window.points}));
+ }
+ }
+ else
+ localStorage.setItem(save['file name'], JSON.stringify({data: data, points: window.points}));
+ } else {
+ 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')
+ }
}
c.putImageData(window.points.history[window.points.history.last].data, 0, 0);
}
+window.load = function() {
+ var file = JSON.parse(localStorage.getItem(load.file));
+ var img = document.createElement('img');
+ img.src = file.data;
+ console.log(file.data);
+ img.onload = function() {
+ c.clearRect(0, 0, width(), height());
+ c.drawImage(img, 0, 0);
+ window.points = file.points;
+ window.points.history = [{ data: c.createImageData($c.width(), $c.height()), points: []}, { data: c.getImageData(0, 0, width(), height()), points: file.points}];
+ }
+}
$('.menu').tap(function() {
$('#menu').toggleClass('pulled');
@@ -69,6 +91,36 @@ window.save = function() {
$('.save').tap(function() {
$('#save').removeClass('hidden');
})
+ $('.load').tap(function() {
+ $('#load').removeClass('hidden');
+ $('#load li').remove();
+ for( var i = 0, len = localStorage.length; i < len; i++ ) {
+ $('#load ol').append(
+ $('
')
+ );
+ }
+ if( localStorage.length < 1 ) {
+ $('#load ol').append(
+ $('
No Sketch found.
')
+ );
+ }
+ $confirm.find('li').off('tap').tap(function(e) {
+ $(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
+ $(this).attr('aria-selected', 'true');
+ })
+ })
+ $('#pro').click(function() {
+ $('#save ol:nth-of-type(2) li').each(function() {
+ if( $(this).find('span').html() !== 'Transparent' ) {
+ $(this).addClass('hidden');
+ $(this).removeAttr('aria-selected');
+ }
+ else $(this).attr('aria-selected', 'true');
+ })
+ })
+ $('#exp').click(function() {
+ $('#save ol:nth-of-type(2) li').removeClass('hidden');
+ })
$c.last().on('touchstart', function(e) {
var xy = relative(e.changedTouches[0].pageX, e.changedTouches[0].pageY);
startPoint(xy.x, xy.y);
@@ -126,28 +178,31 @@ window.save = function() {
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;
- }
+ $confirm.each(function() {
+
+ $(this).find('li').click(function(e) {
+ $(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
+ $(this).attr('aria-selected', 'true');
})
- $(this).parents('form').addClass('hidden');
- window[v]();
- })
- $confirm.find('button').first().tap(function(e) {
- e.preventDefault();
- $(this).parents('form').addClass('hidden');
+ $(this).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' && key !== 'file' ) value = value.toLowerCase();
+ window[v][key] = value;
+ }
+ })
+ $(this).parents('form').addClass('hidden');
+ window[v]();
+ })
+ $(this).find('button').first().click(function(e) {
+ e.preventDefault();
+ $(this).parents('form').addClass('hidden');
+ })
+
})
// Value Selector Callers
diff --git a/Mobile/manifest.webapp b/Mobile/manifest.webapp
index 060082d..e644881 100644
--- a/Mobile/manifest.webapp
+++ b/Mobile/manifest.webapp
@@ -1,7 +1,7 @@
{
"name": "Sketchy",
"description": "Free Sketch/Paint app",
- "version": "1.1",
+ "version": "1.2",
"fullscreen": "true",
"type": "privileged",
"launch_path": "/index.html",
diff --git a/README.md b/README.md
index 4dc474d..3ea4065 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,10 @@ Firefox Marketplace: https://marketplace.firefox.com/app/sketchy/
Changelog
=========
+**1.2**
+* Added an option to save sketches as a project, so they are editable[1]
+* Made Firefox Desktop / Firefox Android versions working ( was blocked by [1] )
+
**1.1**
* Added "About"
* No load-time for Mobile
diff --git a/Web/LICENSE b/Web/LICENSE
deleted file mode 100644
index c42e6b5..0000000
--- a/Web/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-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.
diff --git a/Web/README.md b/Web/README.md
deleted file mode 100644
index 857ebfe..0000000
--- a/Web/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Brush
-=====
-
-An image manipulation tool written in Javascript
diff --git a/Web/css/color-picker.css b/Web/css/color-picker.less
similarity index 100%
rename from Web/css/color-picker.css
rename to Web/css/color-picker.less
diff --git a/Web/css/imgs/load.png b/Web/css/imgs/load.png
new file mode 100644
index 0000000..193d42f
Binary files /dev/null and b/Web/css/imgs/load.png differ
diff --git a/Web/css/main.css b/Web/css/main.css
new file mode 100644
index 0000000..0dfc34b
--- /dev/null
+++ b/Web/css/main.css
@@ -0,0 +1,604 @@
+@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');
+}
+/* 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(#808080, transparent), linear-gradient(90deg, #ff0000, #ff2b00, #ff5500, #ff8000, #ffaa00, #ffd500, #ffff00, #d4ff00, #aaff00, #80ff00, #55ff00, #2bff00, #00ff00, #00ff2b, #00ff55, #00ff80, #00ffaa, #00ffd5, #00ffff, #00d4ff, #00aaff, #007fff, #0055ff, #002bff, #0000ff, #2a00ff, #5500ff, #7f00ff, #aa00ff, #d400ff, #ff00ff, #ff00d4, #ff00aa, #ff0080, #ff0055, #ff002b, #ff0000);
+ -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;
+}
+/* ----------------------------------
+* 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;
+}
+/* ----------------------------------
+ * 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%;
+ overflow: auto;
+}
+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, 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(95%);
+ 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(49.5%);
+ 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;
+}
+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;
+}
+.separator.long {
+ background: url('imgs/div_line_lg_black.png');
+}
+.separator.small {
+ background: url('imgs/div_line_sm_black.png');
+}
+.separator.left {
+ float: left;
+}
+.separator.right {
+ float: right;
+}
+.separator.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 #e3e3e3;
+ 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;
+}
+.picker .color-picker,
+.about .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;
+}
+.about a,
+.about a:link,
+.about a:visited,
+.about a:active {
+ color: white;
+}
+.about .close {
+ background: #262626;
+ color: white;
+ border: 1px solid gray;
+}
+.about p {
+ font-size: 11pt;
+}
+.about span {
+ font-size: 8pt;
+}
+header {
+ width: 100%;
+ height: 5.3rem;
+ background: url('imgs/header_bg_black.png');
+}
+header button {
+ width: 5rem;
+ height: 5rem;
+}
+header .menu {
+ background: url('imgs/menu.png') -12px center no-repeat;
+ float: left;
+}
+header .menu:active {
+ background: url('imgs/menu.png') -12px center no-repeat, url('imgs/bg_overlay_pressed_1.png') left no-repeat;
+}
+header .save {
+ background: url('imgs/download.png') center center no-repeat;
+ float: right;
+}
+header .save:active {
+ background: url('imgs/download.png') center center no-repeat, url('imgs/bg_overlay_pressed_2.png') center center;
+}
+header .load {
+ background: url('imgs/load.png') center center no-repeat;
+ float: right;
+}
+header .load:active {
+ background: url('imgs/load.png') center center no-repeat, url('imgs/bg_overlay_pressed_2.png') center center;
+}
+header #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;
+}
+#menu.pulled {
+ left: 0;
+ transition: left 0.2s ease-out;
+}
+#menu button[id^='set'],
+#menu p,
+#menu .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;
+}
+#menu span {
+ float: right;
+ font-size: 7pt;
+}
+#menu div[role='slider'] {
+ width: 60%;
+ float: right;
+ margin: 0 2rem 0 0;
+}
+#menu div[role='slider'] div {
+ overflow: visible;
+}
+#menu div[role='slider'] div button {
+ margin-top: -3.4rem;
+ left: 0%;
+}
+#menu hr {
+ clear: both;
+ padding: 0.7rem 0;
+ margin-bottom: 0.7rem;
+ border: none;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+}
+#menu *[class^='icon'] {
+ display: block;
+ margin: 1rem 0.5rem;
+}
+#menu *[class^='icon']:nth-of-type(2) {
+ padding-top: 0.5rem;
+}
+#menu *[class^='icon']:before {
+ content: '';
+ background-size: 2rem;
+ width: 2rem;
+ height: 2rem;
+ display: block;
+ float: left;
+ margin: -0.3rem 0.5rem 0 0;
+}
+#menu .icon-settings:before {
+ background-image: url('imgs/settings.png');
+}
+#menu .icon-clear:before {
+ background-image: url('imgs/clear.png');
+}
+#menu .icon-undo:before {
+ background-image: url('imgs/undo.png');
+}
+#menu .icon-redo:before {
+ background-image: url('imgs/redo.png');
+}
+#menu .options {
+ display: block;
+ margin-top: 1rem;
+}
+#menu .bottom {
+ position: absolute;
+ bottom: 5rem;
+ width: 100%;
+}
+#menu .bottom button[class^='icon'] {
+ margin-left: 3.5rem;
+}
+#menu .bottom button {
+ margin-left: 5rem;
+}
diff --git a/Web/css/main.less b/Web/css/main.less
index ea83e2e..0748cce 100644
--- a/Web/css/main.less
+++ b/Web/css/main.less
@@ -1,4 +1,7 @@
@import 'fonts';
+@import 'color-picker';
+@import 'seekbars';
+@import 'value_selector';
html, body {
@@ -148,6 +151,14 @@ header {
}
}
+ .load {
+ background: url('imgs/load.png') center center no-repeat;
+ float: right;
+ &:active {
+ background: url('imgs/load.png') center center no-repeat, url('imgs/bg_overlay_pressed_2.png') center center;
+ }
+ }
+
#title {
color: white;
font-size: 11pt;
diff --git a/Web/css/seekbars.css b/Web/css/seekbars.less
similarity index 100%
rename from Web/css/seekbars.css
rename to Web/css/seekbars.less
diff --git a/Web/css/switches.css b/Web/css/switches.less
similarity index 100%
rename from Web/css/switches.css
rename to Web/css/switches.less
diff --git a/Web/css/value_selector.css b/Web/css/value_selector.less
similarity index 99%
rename from Web/css/value_selector.css
rename to Web/css/value_selector.less
index 0a3493c..1cc41f5 100644
--- a/Web/css/value_selector.css
+++ b/Web/css/value_selector.less
@@ -22,6 +22,7 @@ form[role="dialog"][data-type="value-selector"] > section {
-moz-box-sizing: padding-box;
width: 100%;
height: 100%;
+ overflow: auto;
}
form[role="dialog"][data-type="value-selector"] h1 {
diff --git a/Web/index.html b/Web/index.html
index 127de7d..1dee6ad 100644
--- a/Web/index.html
+++ b/Web/index.html
@@ -5,12 +5,7 @@
Sketchy
-
-
-
-
-
-
+
@@ -22,6 +17,7 @@
Sketchy
+
@@ -132,14 +128,23 @@
+
+
@@ -180,13 +198,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/Web/js/desktop.js b/Web/js/desktop.js
index 205fc3d..6b975e0 100644
--- a/Web/js/desktop.js
+++ b/Web/js/desktop.js
@@ -2,41 +2,42 @@
$(window).resize(sizeAndPos);
-// Check for update
-
-function save() {
- var cData = c.getImageData(0, 0, width(), height());
- switch(save.background) {
- case 'white': {
- c.fillStyle = 'white';
- c.globalCompositeOperation = 'destination-over';
- c.fillRect(0, 0, width(), height());
- c.fillStyle = settings.color;
- c.globalCompositeOperation = settings.composite;
- break;
- }
- case 'current color': {
- c.fillStyle = settings.color;
- c.globalCompositeOperation = 'destination-over';
- c.fillRect(0, 0, width(), height());
- c.fillStyle = settings.color;
- c.globalCompositeOperation = settings.composite;
- break;
- }
- }
- var data = $c[0].toDataURL();
- window.open(data, '_blank').focus();
-
- c.putImageData(cData, 0, 0);
-
-}
-
$('.menu').click(function() {
$('#menu').toggleClass('pulled');
})
$('.save').click(function() {
$('#save').removeClass('hidden');
})
+ $('.load').click(function() {
+ $('#load').removeClass('hidden');
+ $('#load li').remove();
+ for( var i = 0, len = localStorage.length; i < len; i++ ) {
+ $('#load ol').append(
+ $('
')
+ );
+ }
+ if( localStorage.length < 1 ) {
+ $('#load ol').append(
+ $('
No sketch found.
')
+ );
+ }
+ $confirm.find('li').off('click').click(function(e) {
+ $(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
+ $(this).attr('aria-selected', 'true');
+ })
+ })
+ $('#pro').click(function() {
+ $('#save ol:nth-of-type(2) li').each(function() {
+ if( $(this).find('span').html() !== 'Transparent' ) {
+ $(this).addClass('hidden');
+ $(this).removeAttr('aria-selected');
+ }
+ else $(this).attr('aria-selected', 'true');
+ })
+ })
+ $('#exp').click(function() {
+ $('#save ol:nth-of-type(2) li').removeClass('hidden');
+ })
$c.last().on('mousedown', function(e) {
e.preventDefault();
var xy = relative(e.pageX, e.pageY);
@@ -68,7 +69,7 @@ function save() {
// Single
- var $single = $('form[data-type="value-selector"].single');
+ var $single = $('form.single');
$single.find('li').click(function(e) {
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
@@ -90,28 +91,33 @@ function save() {
// Confirm
- var $confirm = $('form[data-type="value-selector"].confirm');
+ var $confirm = $('form.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().toLowerCase();
- window[v][key] = value;
- }
+ $confirm.each(function() {
+
+ $(this).find('li').click(function(e) {
+ $(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
+ $(this).attr('aria-selected', 'true');
})
- $(this).parents('form').addClass('hidden');
- window[v]();
- })
- $confirm.find('button').first().click(function(e) {
- e.preventDefault();
- $(this).parents('form').addClass('hidden');
+ $(this).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' && key !== 'file' ) value = value.toLowerCase();
+ window[v][key] = value;
+ }
+ })
+ $(this).parents('form').addClass('hidden');
+ window[v]();
+ })
+ $(this).find('button').first().click(function(e) {
+ e.preventDefault();
+ $(this).parents('form').addClass('hidden');
+ })
+
})
// Value Selector Callers
diff --git a/Web/js/main.js b/Web/js/main.js
index 4dcd0eb..5671280 100644
--- a/Web/js/main.js
+++ b/Web/js/main.js
@@ -35,4 +35,65 @@ $(document).ready(function() {
nope: ['js/desktop.js', 'js/libs/color-picker.js']
})
+
+ function save() {
+ switch(save.background) {
+ case 'white': {
+ c.fillStyle = 'white';
+ c.globalCompositeOperation = 'destination-over';
+ c.fillRect(0, 0, width(), height());
+ c.fillStyle = settings.color;
+ c.globalCompositeOperation = settings.composite;
+ break;
+ }
+ case 'current color': {
+ c.fillStyle = settings.color;
+ c.globalCompositeOperation = 'destination-over';
+ c.fillRect(0, 0, width(), height());
+ c.fillStyle = settings.color;
+ c.globalCompositeOperation = settings.composite;
+ break;
+ }
+ }
+
+ var data = $c[0].toDataURL();
+
+ if( save.type == 'sketchy project' ) {
+ if( localStorage.getItem(save['file name']) ) {
+ if( confirm('A sketch with this name already exists. Do you want to overwrite ' + save['file name']) + '?' ) {
+ localStorage.setItem(save['file name'], JSON.stringify({data: data, points: window.points}));
+ }
+ }
+ else
+ localStorage.setItem(save['file name'], JSON.stringify({data: data, points: window.points}));
+ } else {
+ window.open(data, '_blank').focus();
+ }
+
+ c.putImageData(window.points.history[window.points.history.last].data, 0, 0);
+ }
+
+ function load() {
+ var file = JSON.parse(localStorage.getItem(load.file));
+ var img = document.createElement('img');
+ img.src = file.data;
+ img.onload = function() {
+ c.clearRect(0, 0, width(), height());
+ c.drawImage(img, 0, 0);
+ window.points = file.points;
+ window.points.history = [{ data: c.createImageData($c.width(), $c.height()), points: []}, { data: c.getImageData(0, 0, width(), height()), points: file.points}];
+ }
+ }
+ window.load = load;
+ window.save = save;
+
+ // Check for Update
+
+ var request = navigator.mozApps.getSelf();
+
+ request.onsuccess = function() {
+ var manifest = this.manifest;
+
+ }
+
})
diff --git a/Web/js/mobile.css b/Web/js/mobile.css
new file mode 100644
index 0000000..e69de29
diff --git a/Web/js/mobile.js b/Web/js/mobile.js
index 8b07849..12b5ea9 100644
--- a/Web/js/mobile.js
+++ b/Web/js/mobile.js
@@ -1,207 +1,196 @@
"use strict";
-$(document).ready(function() {
-
// Open External Links in browser
-$('*').click(function(e) {
- e.preventDefault();
+$('.menu').tap(function() {
+ $('#menu').toggleClass('pulled');
})
-
-$('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
- }
- })
+$('.save').tap(function() {
+ $('#save').removeClass('hidden');
})
-
-function save() {
- var cData = c.getImageData(0, 0, width(), height());
- switch(save.background) {
- case 'white': {
- c.fillStyle = 'white';
- c.globalCompositeOperation = 'destination-over';
- c.fillRect(0, 0, width(), height());
- c.fillStyle = settings.color;
- c.globalCompositeOperation = settings.composite;
- break;
- }
- case 'current color': {
- c.fillStyle = settings.color;
- c.globalCompositeOperation = 'destination-over';
- c.fillRect(0, 0, width(), height());
- c.fillStyle = settings.color;
- c.globalCompositeOperation = settings.composite;
- break;
- }
+$('.load').tap(function() {
+ $('#load').removeClass('hidden');
+ $('#load li').remove();
+ for( var i = 0, len = localStorage.length; i < len; i++ ) {
+ $('#load ol').append(
+ $('
')
+ );
}
- var data = $c[0].toDataURL();
- window.open(data, '_blank').focus();
-
- c.putImageData(cData, 0, 0);
-
-}
-
- $('.menu').tap(function() {
- $('#menu').toggleClass('pulled');
+ if( localStorage.length < 1 ) {
+ $('#load ol').append(
+ $('
No sketch found.
')
+ );
+ }
+ $confirm.find('li').off('tap').tap(function(e) {
+ $(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
+ $(this).attr('aria-selected', 'true');
})
- $('.save').tap(function() {
- $('#save').removeClass('hidden');
+})
+$('#pro').click(function() {
+ $('#save ol:nth-of-type(2) li').each(function() {
+ if( $(this).find('span').html() !== 'Transparent' ) {
+ $(this).addClass('hidden');
+ $(this).removeAttr('aria-selected');
+ }
+ else $(this).attr('aria-selected', 'true');
})
- $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) {
+})
+$('#exp').click(function() {
+ $('#save ol:nth-of-type(2) li').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;
- if( settings.type == 'eraser' ) return;
+ points[points.length-1].type = '';
+ points[points.length-1].start = undefined;
+ }
+})
- if(window.points.history.last < window.points.history.length-1) {
- window.points.history.splice(window.points.history.last+1);
- }
+// Value Selector
- 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;
- }
- })
+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.each(function() {
- // 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).find('li').click(function(e) {
$(this).parent().find('li[aria-selected]').removeAttr('aria-selected');
$(this).attr('aria-selected', 'true');
})
- $confirm.find('button').last().tap(function(e) {
+ $(this).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().toLowerCase();
+ var value = $(this).parent().find('ol:nth-of-type('+i+') li[aria-selected] span').html();
+ if( key !== 'file name' && key !== 'file' ) value = value.toLowerCase();
window[v][key] = value;
}
})
$(this).parents('form').addClass('hidden');
window[v]();
})
- $confirm.find('button').first().tap(function(e) {
+ $(this).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];
- if( target == 'color' ) {
- return $(this).tap(function() {
- $('.picker').removeClass('hidden');
- })
- }
- $(this).tap(function(e) {
- e.preventDefault();
- $('form[id="' + target + '"]').removeClass('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
+// 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);
- }
+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');
+ }
+}).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;
+})
- // Color Picker
-
- $('.close').tap(function() {
- $(this).parent().addClass('hidden');
- })
+$('#undo').tap(undo);
+$('#redo').tap(redo);
- // Bottom
+$('#about').tap(function() {
+ $('.about').removeClass('hidden');
+})
- $('#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');
- })
-
-});
diff --git a/Web/manifest-web.webapp b/Web/manifest-web.webapp
index 0118bf7..f641d16 100644
--- a/Web/manifest-web.webapp
+++ b/Web/manifest-web.webapp
@@ -1,7 +1,7 @@
{
"name": "Sketchy Web",
"description": "Free Sketch/Paint app",
- "version": "1",
+ "version": "1.2",
"default_locale": "en",
"launch_path": "/Sketchy/Web/index.html",
"icons": {
diff --git a/changelog.html b/changelog.html
index b355fe9..ad5ab46 100644
--- a/changelog.html
+++ b/changelog.html
@@ -4,13 +4,21 @@
Sketchy Changelog
-
1.1
+
+
+
+1.2
+- Added an option to save sketches as a project, so they are editable[1]
+- Made Firefox Desktop / Firefox Android versions working ( was blocked by [1] )
+
+1.1
- Added "About"
- No Load-time for mobile
- Added preloader for images
- Fixed low lineWidth for sketches rendering invisible in Chrome
- Fixed background settings not applying ( save )
- Fixed Email link not working on Mobile
+