📜 ⬆️ ⬇️

Sidebar Gadget Sticky Notes with dock synchronization via DropBox for Windows 7 do it yourself

For a very long time, I was looking for a small notebook for storing important information on a computer that would be on my desktop at work and at home. In Windows 7, there is even a special program called Sticky Notes , which is good for everyone, but it has three significant (for me) minus:
  1. It does not have built-in synchronization with several computers (or rather, it can be done through the same DropBox, but with a tambourine);
  2. It constantly hangs in the taskbar in the list of open windows;
  3. When you press Ctrl + D (minimize all windows), it collapses like any other window. Which is not very convenient.


Also on the network was found the program Evernote Sticky Notes . It also has the last two points of deficiencies, but it allows you to synchronize through an Evernote account. After not prolonged use, I decided to give it up.
So what to do?

First, I'll show you what I got in the end. And I will describe the main features, then how it was all done.
Appearance of the gadget:And here is the settings page:

Key features:
  1. Notes made in the form of a gadget for the sidebar of Windows 7;
  2. Synchronization of stored data via DropBox between multiple computers;
  3. The ability to change the color of notes, font, font size;
  4. Resize notes with the mouse;

Gadget implementation


I decided to make a Windows gadget that would completely satisfy me in all respects.
The mechanism of gadgets in Windows allows you to not interfere in the taskbar, they are not affected by minimizing all the windows, they will still occupy a proud place on the desktop. And if you store the file with the text of the note in the DropBox folder, you can synchronize the notes on several computers.
In order to avoid questions why DropBox was chosen, I will answer immediately: I like it, and I constantly use it, and also determine the folder where DropBox is installed by default is quite simple: this folder is usually located here (in JavaScript):

System.Environment.getEnvironmentVariable("USERPROFILE") + "\\DropBox\\" 

The algorithm of the gadget


The algorithm of the gadget is very simple.
The gadget stores the path to the file, which contains the text with the displayed information. This file is in DropBox. When you change the text in the gadget, the changed information is written to the file. DropBox after changing the file itself synchronizes data between computers, this is already a headache of DropBox.
From time to time using JavaScript, it checks whether the date of the last change of the file with the information that the gadget displays and the real file has changed. If the date has changed, the updated text is loaded (this means that the text of the gadget was changed on another computer, or after turning on the computer DropBox did not have time to update the file with the text of the gadget). Actually everything.
')

Gadget implementation


The gadget itself is essentially a zip archive (albeit with a modified .gadget extension) with a manifest inside (the gadget.xml file) and files for the gadget to work (HTML files, JavaScript scripts, images for the gadget, CSS files). The manifest contains information about the gadget and which file to display the gadget.

gadget.xml
 <?xml version="1.0" encoding="utf-8" ?> <gadget> <name>DropBox </name> <namespace>microsoft.windows</namespace> <version>1.0</version> <author name=" "> <info url="http://sys1c.ru" /> <logo src="Images/icon.png" /> </author> <copyright>© 2012</copyright> <description>    ,    DropBox.</description> <icons> <icon src="Images/icon.png" /> </icons> <hosts> <host name="sidebar"> <base type="HTML" apiVersion="1.0.0" src="main.html" /> <permissions>Full</permissions> <platform minPlatformVersion="1.0" /> </host> </hosts> </gadget> 

Here is what we get in the list of gadgets:


The main work files of the gadget


In order to look at the source code of the gadget, simply change the extension from ".gadget" to ".zip" and unpack it with any archiver.
Here is the main HTML document that does all the work.
main.html
 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=Unicode" /> <title>DropBox </title> <style type="text/css"> body { margin: 0; } #textBox { border: none; position: absolute; font-size: 9pt; font-family: Segoe Print, Segoe Script, Segoe UI; background: clear; overflow: auto; } #erase_btn { position: absolute; left: 2px; bottom: 2px; width: 16px; height: 16px; border: none; z-index: 3; border-width: 0; } </style> <script type="text/javascript" src="main.js"></script> </head> <body unselectable="on" scroll="no" onload="initializeMain()"> <g:background id="backgroundObject" style="position:absolute;z-index:-1"/> <textarea id="textBox" onkeyup="OnTextChanged()" style="left:0px;top:0px;padding:15px 15px 15px 15px;"></textarea> <img id="rightGrippie" src="Images/grippie.png" style="position:absolute;right:6px; filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);"/> <img id="bottomGrippie" src="Images/grippie.png" style="position:absolute;bottom:6px;"/> <div onmousedown="resizeTimer(handleRight)" id="handleRight" style="width:16px;height:190px;position:absolute;right:0px;top:0px;cursor:e-resize;z-index:2;"> <img src="Images/spacer.gif" style="width:100%; height:100%"/> </div> <div onmousedown="resizeTimer(handleBottom)" id="handleBottom" style="position:absolute;height:16px;left:0px;bottom:0px;cursor:s-resize;margin:0pxz-index:2;"> <img src="Images/spacer.gif" style="width:100%; height:100%"/> </div> <div onmousedown="resizeTimer(handleCorner)" id="handleCorner" style="width:17px;height:17px;position:absolute;right:0px;bottom:0px;cursor:se-resize;z-index:2;"> <img src="Images/icon_resize.gif" style="width:16px; height:16px; z-index:3;"/> </div> <span onclick="eraseText()" tabindex="1"><img id="erase_btn" src="Images/erase_btn.png" title="" /></span> </body> </html> 

The main script, in which the text information is loaded and saved, checked at intervals for file changes, etc.
main.js
 var width, height; //     var textFileName; //      var fs; //  FileSystemObject var timer, timerInterval; //           var dateLastMod; //     var startWidth, startHeight; //      var basey, basex; //  //   function initializeMain() { //    System.Gadget.settingsUI = "settings.html"; System.Gadget.onSettingsClosed = updateSettings; fs = new ActiveXObject("Scripting.FileSystemObject"); //       LoadTextFile(); updateSettings(); updateDisplay(); //      timer = setInterval(checkText, updateinterval * 1000 * 60); //    } //    Base64 function base64_decode (data) { var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, dec = "", tmp_arr = []; if (!data) { return data; } data += ''; do { // unpack four hexets into three octets using index points in b64 h1 = b64.indexOf(data.charAt(i++)); h2 = b64.indexOf(data.charAt(i++)); h3 = b64.indexOf(data.charAt(i++)); h4 = b64.indexOf(data.charAt(i++)); bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; o1 = bits >> 16 & 0xff; o2 = bits >> 8 & 0xff; o3 = bits & 0xff; if (h3 == 64) { tmp_arr[ac++] = String.fromCharCode(o1); } else if (h4 == 64) { tmp_arr[ac++] = String.fromCharCode(o1, o2); } else { tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); } } while (i < data.length); dec = tmp_arr.join(''); return dec; } //       function LoadTextFile() { //     (    ) var text = ""; textFileName = System.Gadget.Settings.read("textfilename"); if (textFileName){ if (fs.FileExists(textFileName)){ var f = fs.OpenTextFile(textFileName, 1, true, -1); if (!f.AtEndOfStream) text = f.ReadAll(); f.Close(); } else { var f = fs.CreateTextFile(textFileName, true, true); f.Close(); } } else { try { //     host.db  DropBox var dbPath = System.Environment.getEnvironmentVariable("APPDATA"); var fconfig = fs.OpenTextFile(dbPath + "\\Dropbox\\host.db", 1, false, 0); var s = fconfig.ReadLine(); var folderPath = base64_decode(fconfig.ReadLine()); } catch(e) { //       ,       var folderPath = System.Environment.getEnvironmentVariable("USERPROFILE") + "\\Dropbox"; } textFileName = folderPath + "\\Tasks.txt"; if (fs.FileExists(textFileName)){ var f = fs.OpenTextFile(textFileName, 1, true, -1); if (!f.AtEndOfStream) text = f.ReadAll(); f.Close(); } else { var f = fs.CreateTextFile(textFileName, true, true); f.Close(); } } //      dateLastMod = fs.GetFile(textFileName).dateLastModified; //     if (text) textBox.value = text; else textBox.value = ""; } //         ,      function checkText() { var f = fs.GetFile(textFileName); if (f.dateLastModified != dateLastMod){ //    dateLastMod = f.dateLastModified; var fi = fs.OpenTextFile(textFileName, 1, true, -1); if (!f.AtEndOfStream) textBox.value = fi.ReadAll(); fi.Close(); } } //   function updateSettings() { var Color = System.Gadget.Settings.read("backgroundColor"); if (Color) textBox.style.backgroundColor = Color; else textBox.style.backgroundColor = "FFFFB9"; var fontname = System.Gadget.Settings.read("fontname"); if (fontname) textBox.style.fontFamily = fontname; else textBox.style.fontFamily = "Segoe UI"; var fontsize = System.Gadget.Settings.read("fontsize"); if (fontsize) textBox.style.fontSize = fontsize + "pt"; else { fontsize = "10" textBox.style.fontSize = "10pt"; } var tempWidth = System.Gadget.Settings.read("width"); if (tempWidth) width = tempWidth; else width = "200"; var tempHeight = System.Gadget.Settings.read("height"); if (tempHeight) height = tempHeight; else height = "200"; var tempupdateinterval = System.Gadget.Settings.read("updateinterval"); if (tempupdateinterval) updateinterval = tempupdateinterval; else updateinterval = 1; var tempFileName = System.Gadget.Settings.read("textfilename"); if (tempFileName) textFileName = tempFileName; LoadTextFile(); //      document.body.style.backgroundColor = textBox.style.backgroundColor; document.body.style.scrollbarFaceColor = textBox.style.backgroundColor; document.body.style.scrollbarFaceColor = textBox.style.backgroundColor; document.body.style.scrollbarTrackColor = textBox.style.backgroundColor; document.body.style.scrollbarShadowColor = textBox.style.backgroundColor; document.body.style.scrollbarHighlightColor = textBox.style.backgroundColor; document.body.style.scrollbar3dlightColor = textBox.style.backgroundColor; document.body.style.scrollbarDarkshadowColor = textBox.style.backgroundColor; //   System.Gadget.Settings.write("backgroundColor", textBox.style.backgroundColor); System.Gadget.Settings.write("fontname", textBox.style.fontFamily); System.Gadget.Settings.write("fontsize", fontsize); System.Gadget.Settings.write("width", width); System.Gadget.Settings.write("height", height); System.Gadget.Settings.write("textfilename", textFileName); System.Gadget.Settings.write("updateinterval", updateinterval); } //      function OnTextChanged() { var f = fs.CreateTextFile(textFileName, true, true); f.Write(textBox.value); f.Close(); } //   function eraseText() { textBox.value = ""; OnTextChanged(); } //  function updateDisplay() { document.body.style.height = height; document.body.style.width = width; textBox.style.width = width - 16; handleBottom.style.width = width - 18; textBox.style.height = height - 16; handleRight.style.height = height - 18; rightGrippie.style.top = Math.floor(height / 2 - 13); bottomGrippie.style.left = Math.floor(width / 2 - 13); } //    function resizeTimer(field) { field.setCapture(); startWidth = parseInt(document.body.style.width); startHeight = parseInt(document.body.style.height); basey = event.y; basex = event.x; field.onmousemove = function () { doResize(field); } field.onmouseup = function () { field.releaseCapture(); field.onmousemove = null; field.onmouseup = null; doResize(field); System.Gadget.Settings.write("width", width); System.Gadget.Settings.write("height", height); } } function doResize(field) { if (field == handleRight || field == handleCorner) { width = startWidth + event.x - basex; width = width < 40 ? 40 : width; } if (field == handleBottom || field == handleCorner) { height = startHeight + event.y - basey; height = height < 40 ? 40 : height; } updateDisplay(); } 

How to install a gadget


Attention! For the operation of the gadget you need the installed DropBox. And the path to the synchronized folder should be the same as DropBox offers during installation! If suddenly it is not so, then nothing terrible, you can install the gadget, open the settings and manually specify the path to the file in which the text of our note will be stored.
Download the gadget ( at the end of the article ) and run it:

Click "Install". Done, the gadget is installed, and a note appears on the desktop that can already be used.

Minuses


All the same, no cons anywhere. There are problems that at the moment did not work out.
  1. If the DropBox folder is in another place, different from where it is installed by default, the gadget will not work right away. You will need to open the gadget settings and specify the path to the file. This minus is eliminated.
  2. No formatting in the note. Only plain text, no italics, bold, strikethrough text, etc. There was an attempt to tie WYSIWYG editors ( TinyMCE , CKEditor ) to the gadget, but it wasn’t possible to make them work properly in the gadget out of the box.

Let's sum up


For myself, I got exactly what I wanted: a simple and convenient gadget, which is with me both at home and at work.
I also want to say separately that for people who know HTML + CSS + JavaScript well, it’s very easy to make a good gadget that makes life easier.

Download gadget

I hope my article was useful for you.

PS: Fixed found errors.
Now the DropBox sync folder is defined programmatically using JavaScript (special thanks to the isden user for the link ). Also, when changing the file name in the settings, changes are accepted immediately.

Source: https://habr.com/ru/post/151774/


All Articles