Jelajahi Sumber

version 0.3.0: added a save banner/notification feature

Gildas lormeau 14 tahun lalu
induk
melakukan
ca12db8e47

+ 1 - 1
WebContent/core/manifest.json

@@ -4,7 +4,7 @@
 		"16": "resources/icon_16.png",
 		"48": "resources/icon_48.png",
 		"128": "resources/icon_128.png" },
-	"version": "0.2.33",
+	"version": "0.3.0",
 	"description": "Page processor used by SingleFile",
 	"background_page" : "pages/background.html",
 	"content_scripts": [ {

+ 1 - 1
WebContent/ui/manifest.json

@@ -4,7 +4,7 @@
 		"16": "resources/icon_16.png",
 		"48": "resources/icon_48.png",
 		"128": "resources/icon_128.png" },
-	"version": "0.2.33",
+	"version": "0.3.0",
 	"description": "SingleFile helps you to archive a complete page into a single HTML file",
 	"background_page" : "pages/background.html",
 	"options_page": "pages/options.html",

+ 52 - 0
WebContent/ui/pages/banner.css

@@ -0,0 +1,52 @@
+body {
+	overflow: hidden;
+	margin-top: 4px;
+	margin-left: 4px;
+	margin-bottom: 0px;
+	margin-right: 0px;
+	background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0.5, rgb(253,
+		237, 166) ), color-stop(1, rgb(250, 229, 146) ) );
+}
+
+.link {
+	color: black;
+	font-family: Arial;
+	text-decoration: none;
+	font-size: 11pt;
+	padding-left: 20px;
+}
+
+.link:hover {
+	text-decoration: underline;
+}
+
+.link::before {
+	background-image: url(../resources/icon_19_save.png);
+	height: 19px;
+	width: 19px;
+	content: " ";
+	display: inline-block;
+	position: relative;
+	top: 3px;
+	left: -14px;
+}
+
+.close-button {
+	text-shadow: 1px 1px #333;
+	display: inline-block;
+	height: 14px;
+	width: 14px;
+	background-image: url(../resources/icon_close.png);
+	font-family: sans-serif;
+	font-weight: bold;
+	opacity: .4;
+	position: absolute;
+	right: 6px;
+	top: 10px;
+	cursor: default;
+}
+
+.close-button:hover {
+	-webkit-transition: opacity .2s ease-out;
+	opacity: 1;
+}

+ 12 - 0
WebContent/ui/pages/banner.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" href="banner.css">
+<title>SingleFile banner</title>
+</head>
+<body>
+	<a id="link" class="link">Click here to save the page</a><a id="close" class="close-button"></a>
+	<script src="../scripts/content/banner.js"></script>
+</body>
+</html>

+ 2 - 2
WebContent/ui/pages/help.css

@@ -19,7 +19,7 @@ body>div {
 	-webkit-box-shadow: #888 2px 2px 2px;
 }
 
-div>object {
+div>iframe {
 	margin-top: 30px;
 	margin-left: auto;
 	margin-right: auto;
@@ -71,7 +71,7 @@ ol>li>ul>li {
 	background-image: url(../resources/options_screen.png);
 	background-repeat: no-repeat;
 	background-position: center center;
-	height: 500px;
+	height: 562px;
 }
 
 #title {

+ 46 - 41
WebContent/ui/pages/help.html

@@ -8,39 +8,34 @@
 <body>
 <div>
 <div id="titleBorder">
-<h2><img src="../resources/icon_48.png" id="titleIcon"><span id="title">SingleFile help</span></h2>
-<h4>SingleFile helps you to archive a complete page into a single HTML file.</h4>
+<h2>SingleFile help</h2>
+<h4>Archive a complete page into a single HTML file</h4>
 </div>
 <span id="index"><a href="#instructions">Instructions</a> - <a href="#demo">Demo</a> - <a href="#options">Options description</a> - <a href="#notes">Technical notes</a> - <a href="#knownIssues">Known issues</a> - <a href="#unknownIssues">Unknown issues</a></span>
 <hr>
 <ol>
 	<li><a id="instructions">Instructions</a>
 	<ul>
-		<li>wait until the page is fully loaded : you may need to scroll down the entire page and hover dynamic document elements (e.g. "rollover" images) to be sure all elements
-		are loaded</li>
-		<li>click on the SingleFile icon <img src="../resources/icon_19.png" id="icon"> in the Chrome toolbar or press Ctrl-Shift-S or use context menu to launch page
-		processing</li>
-		<li>wait until the shadow disappears then hit Ctrl-S or select "Save as" in the wrench menu and save the page</li>
-		<li>all images, style sheets and frame contents are embedded into the ".htm" saved file</li>
+		<li>wait until the page is fully loaded : you may need to scroll down the entire page and hover dynamic document elements (e.g. "rollover" images) to be sure all elements are loaded</li>
+		<li>click on the SingleFile icon <img src="../resources/icon_19.png" id="icon"> in the Chrome toolbar (or press Ctrl-Shift-S or use context menu) to launch page processing</li>
+		<li>wait until the save banner appears at the top the page</li>
+		<li>click on the link into the banner to save the page in default download folder</li>
 	</ul>
+	<p>
+		Since version 0.3.0 of SingleFile it is not possible save the page with Chrome "Save as" dialog anymore. If you still want to use this feature then uncheck <span class="option">display save banner</span> and <span class="option">display save notification</span> in the options page. 
+	</p>
 	</li>
 
-	<li><a id="demo">Demo : SingleFile advantages over default file save</a>
-	<div><object width="480" height="385">
-		<param name="movie" value="http://www.youtube.com/v/D99LfOF3qis&hl=fr_FR&fs=1&">
-		<param name="allowFullScreen" value="true">
-		<param name="allowscriptaccess" value="always">
-		<embed src="http://www.youtube.com/v/D99LfOF3qis&hl=fr_FR&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></object>
-	</div>
+	<li><a id="demo">Demo</a>
+	<div><iframe width="420" height="315" src="http://www.youtube.com/embed/pFCJAFvc_MA" frameborder="0" allowfullscreen></iframe></div>
 	<li><a id="options">Options description</a>
 
-	<p>You can customize the way SingleFile process a document through the options page. Right-click on SingleFile icon <img src="../resources/icon_19.png" id="icon"> in the
-	Chrome toolbar and select "Options" in the context menu to open the options page.</p>
+	<p>You can customize the way SingleFile process a document through the options page. Right-click on SingleFile icon <img src="../resources/icon_19.png" id="icon"> in the Chrome toolbar and select "Options" in the context menu to open the options page.</p>
 	<div class="screenshot"></div>
 	<p>Details :</p>
 	<ul>
 		<li><span class="option">remove frames</span>
-		<p>Check this option to remove all frames on the page. It may help to reduce the file size, to remove some ads and to view saved pages on IE8.</p>
+		<p>Check this option to remove all frames on the page. It may help to reduce the file size, to remove some ads and must be checked to view saved pages on IE.</p>
 		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</li>
 
@@ -49,36 +44,41 @@
 		<p class="notice">It is recommended to <u>check</u> this option</p>
 		</li>
 
-		<li><span class="option">remove scripts</span>
-		<p>Check this option if you do not want to save scripts. Most of the time, you do not need scripts in the saved page. Thus they can alter it. Nevertheless if you want to save
-		page dynamic behavior then uncheck this option. If you uncheck this option then you should also check <span class="option">process raw document</span> option to keep page integrity.</p>
-		<p class="notice">It is recommended to <u>check</u> this option</p>
-		</li>
-
 		<li><span class="option">remove hidden elements</span>
 		<p>Check this option to remove all hidden elements (<code>visibility = "hidden"</code>&nbsp;or&nbsp;<code>display = "none"</code>&nbsp;or&nbsp;<code>opacity = "0"</code> CSS
 		property values). This option may alter the document but can considerably reduce the saved file size.</p>
 		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</li>
 
-		<li><span class="option">remove unused CSS rules</span>
-		<p>Check this option to remove all CSS rules that do not match any element. This option may alter the document but can considerably reduce the saved file size. If you check
-		this option, it may also introduce some incompatibilities issues in the saved page when opening it into another browser (i.e. not based on Webkit).</p>
-		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
+		<li><span class="option">add entry in the context menu</span>
+		<p>Check this option to launch processing on a page with page context menu. This option also helps to process only the selected area in the page.</p>
+		<p class="notice">It is recommended to <u>check</u> this option</p>
 		</li>
-		
-		<li><span class="option">display a context menu entry</span>
-		<p>Check this option to launch processing on a page with context menu. This option also helps to process only the selected area in the page.</p>
+
+		<li><span class="option">display save banner</span> (only with Chrome 15+)
+		<p>Check this option to display a banner with a download link at the top of the page when processing is finished. If this option and <span class="option">display save notification</span> are not checked then you must manually save the page through Chrome "Save as" dialog (make sure that "Web page, Complete" option is selected) after it has been processed.</p>
+		<p class="notice">It is recommended to <u>check</u> this option or <span class="option">display save notification</span> option</p>
+		</li>
+
+		<li><span class="option">display save notification</span> (only with Chrome 16+)
+		<p>Check this option to display a notification with a download link when processing is finished. If this option and <span class="option">display save banner</span> are not checked then you must manually save the page through Chrome "Save as" dialog (make sure that "Web page, Complete" option is selected) after it has been processed.</p>
+		<p class="notice">It is recommended to <u>check</u> this option or <span class="option">display save banner</span> option</p>
+		</li>
+
+		<li><span class="option">remove scripts</span>
+		<p>Check this option if you do not want to save scripts. Most of the time, you do not need scripts in the saved page. Thus they can alter it. Nevertheless if you want to save
+		page dynamic behavior then uncheck this option. If you uncheck this option then you should also check <span class="option">process raw document</span> option to keep page integrity.</p>
 		<p class="notice">It is recommended to <u>check</u> this option</p>
 		</li>
 
-		<li><span class="option">send archive to PageArchiver</span>
-		<p>Check this option to send the processed page to <a href="https://chrome.google.com/webstore/detail/ihkkeoeinpbomhnpkmmkpggkaefincbn">PageArchiver</a> chrome extension.</p>
+		<li><span class="option">remove unused CSS rules</span>
+		<p>Check this option to remove all CSS rules that do not match any element. This option may alter the document but can considerably reduce the saved file size. If you check
+		this option, it may also introduce some incompatibilities issues in the saved page when opening it into another browser (i.e. not based on Webkit).</p>
 		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</li>
 
-		<li><span class="option">process in background</span>
-		<p>Check this option to process the page in background. Processing in background is usually faster but can alter the page.</p>
+		<li><span class="option">send saved page to PageArchiver</span>
+		<p>Check this option to send the processed page to <a href="https://chrome.google.com/webstore/detail/ihkkeoeinpbomhnpkmmkpggkaefincbn">PageArchiver</a> extension.</p>
 		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</li>
 
@@ -88,8 +88,13 @@
 		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</li>
 
+		<li><span class="option">process in background</span>
+		<p>Check this option to process the page in background. Processing in background is usually faster but can alter the page if there are critical issues with page validity.</p>
+		<p class="notice">It is recommended to <u>uncheck</u> this option</p>
+		</li>
+
 		<li><span class="option">Reset to default options</span>
-		<p>Reset all the options to default (i.e. recommended) state.</p>
+		<p>Reset all the options to default state.</p>
 		</li>
 	</ul>
 	</li>
@@ -97,11 +102,11 @@
 	<li><a id="notes">Technical notes</a>
 	<ul>
 		<li>all images are converted into <a href="http://en.wikipedia.org/wiki/Base64">base64</a></li>
-		<li>frame document contents and automatically saved pages (*) are encoded with <a href="http://en.wikipedia.org/wiki/Utf_8">utf-8 charset</a></li>
+		<li>frame document contents are encoded with <a href="http://en.wikipedia.org/wiki/Utf_8">UTF-8 charset</a></li>
 		<li>encoded contents are injected in the document using <a href="http://en.wikipedia.org/wiki/Data_URI_scheme">data URI scheme</a></li>
 		<li>data URI scheme is supported by the following web browsers: Chrome, Firefox, Opera, Safari, Konqueror and Internet Explorer 8 (limited support: data URIs must be smaller
 		than 32 KB, embedded frames are not supported)</li>
-		<li>SVG images are supported (SVG document is converted into utf-8 but is not processed)</li>
+		<li>SVG images are supported (SVG document is converted into UTF-8 but is not processed)</li>
 	</ul>
 	</li>
 
@@ -111,7 +116,7 @@
 		<li>If you are using <a href="https://chrome.google.com/extensions/detail/odjhifogjcknibkahlpidmdajjpkkcfn">NotScripts</a> extension and have issues when using SingleFile
 		then you must add this line in "CHANGE__PASSWORD__HERE.js" file as described <a href="http://optimalcycling.com/other-projects/notscripts/faq/#mitigation">here</a>:<br>
 		<code>const DO_NOT_MITIGATE_INLINE_SCRIPTS = true;</code></li>
-		<li><code>file:///*</code>, <code>chrome://*</code> and <code>https://chrome.google.com/*</code> URIs cannot be processed</li>
+		<li>For security reasons these URIs cannot be processed:<br><code>file:///*</code>, <code> chrome://*</code>, <code> https://chrome.google.com/*</code></li>
 	</ul>
 	</li>
 
@@ -119,10 +124,10 @@
 	<p>If you find an unknown issue (i.e. frozen process, extra saved files, blank or altered document, tab crash...):</p>
 	<ul>
 		<li>reset SingleFile options</li>
+		<li>if option reseting did not work, try to uncheck <span class="option">display save notification</span> and <span class="option">display save banner</span> and make sure that <span class="option">process in background</span> unchecked: you will need to use Chrome "Save as" dialog to save the page.</li>
 		<li>disable all other extensions to see if there is a conflict</li>
 		<li>if there is a conflict then try to determine against which extension(s)</li>
-		<li>report the issue <a href="https://chrome.google.com/webstore/detail/mpiodijhokgodhhofbcjdecpffjipkle">here</a> with a short description describing how to reproduce it,
-		Chrome version, OS name and version.</li>
+		<li>please report the issue <a href="https://github.com/gildas-lormeau/SingleFile/issues">here</a> with a short description describing how to reproduce the issue, Chrome version, OS name and version.</li>
 	</ul>
 	</li>
 </ol>

+ 12 - 0
WebContent/ui/pages/notification.css

@@ -0,0 +1,12 @@
+body {
+	font-family: sans-serif;
+	font-size: 11pt;
+}
+
+a {
+	width: 290px;
+	display: inline-block;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+}

+ 12 - 0
WebContent/ui/pages/notification.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<link rel="stylesheet" href="notification.css">
+<title>SingleFile notification</title>
+</head>
+<body>
+	<a id="link"></a>
+	<script src="../scripts/bg/notification.js"></script>
+</body>
+</html>

+ 1 - 1
WebContent/ui/pages/options.css

@@ -5,7 +5,7 @@ body {
 body>div {
 	margin-left: auto;
 	margin-right: auto;
-	width: 300px;
+	width: 350px;
 	background-color: #fff;
 	font-family: sans-serif;
 	margin-bottom: 10px;

+ 32 - 18
WebContent/ui/pages/options.html

@@ -7,10 +7,10 @@
 </head>
 <body>
 <div>
-<h2><img alt="SingleFile icon" id="icon" src="../resources/icon_48.png"/>SingleFile</h2>
+<h2>SingleFile</h2>
 <hr>
 <div id="popupContent">	
-	<h4>Basic options:</h4>
+	<h4>Basic options</h4>
 	<div class="option">
 		<label for="removeFramesInput">remove frames <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeFramesInput">
 		<div class="help">
@@ -26,45 +26,52 @@
 		</div>
 	</div>
 	<div class="option">
-		<label for="removeScriptsInput">remove scripts <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeScriptsInput">
+		<label for="removeHiddenInput">remove hidden elements <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeHiddenInput">
 		<div class="help">
-			<p>Check this option if you do not want to save scripts.</p>
-			<p class="notice">It is recommended to <u>check</u> this option</p>		
+			<p>Check this option to remove all hidden elements.</p>
+			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</div>
 	</div>
 	<div class="option">
-		<label for="removeHiddenInput">remove hidden elements <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeHiddenInput">
+		<label for="displayInContextMenuInput">add entry in the context menu <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="displayInContextMenuInput">
 		<div class="help">
-			<p>Check this option to remove all hidden elements.</p>
-			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
+			<p>Check this option to launch processing on a page with context menu.</p>
+			<p class="notice">It is recommended to <u>check</u> this option</p>
 		</div>
 	</div>
 	<div class="option">
-		<label for="removeUnusedCSSRulesInput">remove unused CSS rules <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeUnusedCSSRulesInput">
+		<label for="displayBannerInput">display save banner <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="displayBannerInput">
 		<div class="help">
-			<p>Check this option to remove all CSS rules that do not match any element.</p>
-			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
+			<p>Check this option to display a banner with a download link at the top of the page when processing is finished.</p>
+			<p class="notice">It is recommended to <u>check</u> this option or "display save notification" option</p>
 		</div>
 	</div>
 	<div class="option">
-		<label for="displayInContextMenuInput">add entry into the context menu<img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="displayInContextMenuInput">
+		<label for="displayNotificationInput">display save notification <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="displayNotificationInput">
 		<div class="help">
-			<p>Check this option to launch processing on a page with context menu.</p>
+			<p>Check this option to display a notification with a download link when processing is finished.</p>
+			<p class="notice">It is recommended to <u>check</u> this option or "display save banner" option</p>
+		</div>
+	</div>
+	<h4>Advanced options</h4>
+	<div class="option">
+		<label for="removeScriptsInput">remove scripts <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeScriptsInput">
+		<div class="help">
+			<p>Check this option if you do not want to save scripts.</p>
 			<p class="notice">It is recommended to <u>check</u> this option</p>
 		</div>
 	</div>
-	<h4>Advanced options:</h4>
 	<div class="option">
-		<label for="getContentInput">send archive to PageArchiver <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="getContentInput">
+		<label for="removeUnusedCSSRulesInput">remove unused CSS rules <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="removeUnusedCSSRulesInput">
 		<div class="help">
-			<p>Check this option to send the processed page to PageArchiver chrome extension.</p>
+			<p>Check this option to remove all CSS rules that do not match any element.</p>
 			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</div>
 	</div>
 	<div class="option">
-		<label for="processInBackgroundInput">process in background <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="processInBackgroundInput">
+		<label for="sendToPageArchiverInput">send saved page to PageArchiver <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="sendToPageArchiverInput">
 		<div class="help">
-			<p>Check this option to process the page in background. Processing in background means it won't be blocking.</p>
+			<p>Check this option to send the processed page to PageArchiver chrome extension.</p>
 			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</div>
 	</div>
@@ -75,6 +82,13 @@
 			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
 		</div>
 	</div>
+	<div class="option">
+		<label for="processInBackgroundInput">process in background <img class="question-mark" src="../resources/icon_question_mark.jpg"></label> <input type="checkbox" id="processInBackgroundInput">
+		<div class="help">
+			<p>Check this option to process the page in background. Processing in background means it won't be blocking.</p>
+			<p class="notice">It is recommended to <u>uncheck</u> this option</p>
+		</div>
+	</div>
 	<div class="option">	
 		<a href="help.html" target="SingleSileHelpPage">help</a><button id="resetButton" title="Reset all the options to default (i.e. recommended) state">Reset to default options</button>
 	</div>

TEMPAT SAMPAH
WebContent/ui/resources/options_screen.png


+ 21 - 12
WebContent/ui/scripts/bg/background.js

@@ -69,12 +69,12 @@
 		singlefile.ui.notifyProcessable(tabId, processable(url), reset);
 	}
 
-	function notifyScrapbook(request) {
-		var SCRAPBOOK_EXT_ID = dev ? "imfajgkkpglkdjkjejkefllgajgmhmfp" : "ihkkeoeinpbomhnpkmmkpggkaefincbn";
-		if (request.content)
-			detectExtension(SCRAPBOOK_EXT_ID, function(detected) {
+	function notifyPageArchiver(request) {
+		var PAGEARCHIVER_EXT_ID = dev ? "gneihhijimfbdmoieljdpjldkfbfijaa" : "ihkkeoeinpbomhnpkmmkpggkaefincbn";
+		if (singlefile.config.get().sendToPageArchiver && request.content)
+			detectExtension(PAGEARCHIVER_EXT_ID, function(detected) {
 				if (detected)
-					chrome.extension.sendRequest(SCRAPBOOK_EXT_ID, request);
+					chrome.extension.sendRequest(PAGEARCHIVER_EXT_ID, request);
 			});
 	}
 
@@ -94,33 +94,42 @@
 	});
 
 	chrome.extension.onRequestExternal.addListener(function(request, sender, sendResponse) {
+		var blobBuilder, url;
 		if (request.processStart) {
 			singlefile.ui.notifyProcessStart(request.tabId, request.processingPagesCount);
 			if (request.blockingProcess)
 				chrome.tabs.sendRequest(request.tabId, {
 					processStart : true
 				});
-			notifyScrapbook(request);
+			notifyPageArchiver(request);
 		}
 		if (request.processProgress) {
 			singlefile.ui.notifyProcessProgress(request.index, request.maxIndex);
-			notifyScrapbook(request);
+			notifyPageArchiver(request);
 		}
-		if (request.pageSaved)
-			singlefile.ui.notifySavedPage(request.processed, request.filename);
 		if (request.processEnd) {
 			if (request.blockingProcess)
 				chrome.tabs.sendRequest(request.tabId, {
 					processEnd : true
 				});
-			singlefile.ui.notifyProcessEnd(request.tabId, request.processingPagesCount);
-			notifyScrapbook(request);
+			blobBuilder = new WebKitBlobBuilder();
+			blobBuilder.append((new Uint8Array([ 0xEF, 0xBB, 0xBF ])).buffer);
+			blobBuilder.append(request.content);
+			url = webkitURL.createObjectURL(blobBuilder.getBlob());
+			singlefile.ui.notifyProcessEnd(request.tabId, request.processingPagesCount, singlefile.config.get().displayNotification,
+					singlefile.config.get().displayBanner, url, request.title);
+			notifyPageArchiver(request);
 		}
 		if (request.processError)
 			singlefile.ui.notifyProcessError(request.tabId);
 	});
 	chrome.extension.onRequest.addListener(function(request, sender) {
-		process(sender.tab.id, sender.tab.url);
+		if (request.closeBanner)
+			chrome.tabs.sendRequest(sender.tab.id, {
+				closeBanner : true
+			});
+		else
+			process(sender.tab.id, sender.tab.url);
 	});
 	chrome.browserAction.onClicked.addListener(function(tab) {
 		process(tab.id, tab.url);

+ 20 - 4
WebContent/ui/scripts/bg/config.js

@@ -33,11 +33,14 @@
 			removeObjects : true,
 			removeHidden : false,
 			removeUnusedCSSRules : false,
-			processInBackground : false,
-			displayProcessedPage : true,
-			getContent : false,
+			processInBackground : true,
+			displayProcessedPage : false,
+			getContent : true,
 			getRawDoc : false,
-			displayInContextMenu : true
+			displayInContextMenu : true,
+			sendToPageArchiver : false,
+			displayNotification : false,
+			displayBanner: true
 		};
 	};
 
@@ -55,7 +58,20 @@
 			conf.displayInContextMenu = true;
 			singlefile.config.set(conf);
 		}
+	}
 
+	// migration 0.2.33 -> 0.3.0
+	if (localStorage.config) {
+		var conf = singlefile.config.get();
+		if (typeof conf.displayNotification == "undefined") {
+			conf.sendToPageArchiver = conf.getContent;
+			conf.getContent = true;
+			conf.displayNotification = false;
+			conf.displayBanner = true;
+			conf.processInBackground = true;
+			conf.displayProcessedPage = false;
+			singlefile.config.set(conf);
+		}
 	}
 
 })();

+ 32 - 0
WebContent/ui/scripts/bg/notification.js

@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011 Gildas Lormeau
+ * contact : gildas.lormeau <at> gmail.com
+ * 
+ * This file is part of SingleFile.
+ *
+ *   SingleFile is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SingleFile is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with SingleFile.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function() {
+	var link = document.getElementById("link");
+	var params = location.search.substring(1).split("&");
+	var date = new Date();
+	var time = date.toISOString().split("T")[0] + " " + date.toLocaleTimeString();
+	link.href = decodeURIComponent(params[0]);
+	link.innerText = decodeURIComponent(params[1]);
+	link.download = decodeURIComponent(params[1]) + " (" + time + ")" + ".htm";
+	link.onclick = function() {
+		window.close();
+	};
+})();

+ 49 - 26
WebContent/ui/scripts/bg/options.js

@@ -19,18 +19,27 @@
  */
 (function() {
 
-	var removeScriptsInput, removeFramesInput, removeObjectsInput, removeHiddenInput, removeUnusedCSSRulesInput, processInBackgroundInput, getRawDocInput, getContentInput, displayInContextMenu, bgPage = chrome.extension
-			.getBackgroundPage(), config = bgPage.singlefile.config.get();
-	removeFramesInput = document.getElementById("removeFramesInput");
-	removeScriptsInput = document.getElementById("removeScriptsInput");
-	removeObjectsInput = document.getElementById("removeObjectsInput");
-	removeHiddenInput = document.getElementById("removeHiddenInput");
-	removeUnusedCSSRulesInput = document.getElementById("removeUnusedCSSRulesInput");
-	displayInContextMenuInput = document.getElementById("displayInContextMenuInput");
-	processInBackgroundInput = document.getElementById("processInBackgroundInput");
-	getRawDocInput = document.getElementById("getRawDocInput");
-	getContentInput = document.getElementById("getContentInput");
-	document.getElementById("popupContent").onchange = function() {
+	var removeScriptsInput, removeFramesInput, removeObjectsInput, removeHiddenInput, removeUnusedCSSRulesInput, processInBackgroundInput, getRawDocInput, sendToPageArchiverInput, displayNotificationInput, displayBannerInput, displayInContextMenuInput, bgPage = chrome.extension
+			.getBackgroundPage(), config;
+
+	function refresh() {
+		config = bgPage.singlefile.config.get();
+		removeFramesInput.checked = config.removeFrames;
+		removeScriptsInput.checked = config.removeScripts;
+		removeObjectsInput.checked = config.removeObjects;
+		removeHiddenInput.checked = config.removeHidden;
+		removeUnusedCSSRulesInput.checked = config.removeUnusedCSSRules;
+		displayInContextMenuInput.checked = config.displayInContextMenu;
+		displayNotificationInput.checked = config.displayNotification;
+		displayBannerInput.checked = config.displayBanner;
+		processInBackgroundInput.checked = config.processInBackground;
+		getRawDocInput.checked = config.getRawDoc;
+		sendToPageArchiverInput.checked = config.sendToPageArchiver;
+		if (displayNotificationInput.checked || displayBannerInput.checked)
+			processInBackgroundInput.checked = processInBackgroundInput.disabled = true;
+	}
+
+	function update() {
 		bgPage.singlefile.config.set({
 			removeFrames : removeFramesInput.checked,
 			removeScripts : removeScriptsInput.checked,
@@ -38,25 +47,37 @@
 			removeHidden : removeHiddenInput.checked,
 			removeUnusedCSSRules : removeUnusedCSSRulesInput.checked,
 			displayInContextMenu : displayInContextMenuInput.checked,
+			displayNotification : displayNotificationInput.checked,
+			displayBanner : displayBannerInput.checked,
+			displayProcessedPage : !displayNotificationInput.checked && !displayBannerInput.checked,
 			processInBackground : processInBackgroundInput.checked,
 			getRawDoc : getRawDocInput.checked,
-			getContent : getContentInput.checked
+			sendToPageArchiver : sendToPageArchiverInput.checked
 		});
-	};
-	removeFramesInput.checked = config.removeFrames;
-	removeScriptsInput.checked = config.removeScripts;
-	removeObjectsInput.checked = config.removeObjects;
-	removeHiddenInput.checked = config.removeHidden;
-	removeUnusedCSSRulesInput.checked = config.removeUnusedCSSRules;
-	displayInContextMenuInput.checked = config.displayInContextMenu;
-	processInBackgroundInput.checked = config.processInBackground;
-	getRawDocInput.checked = config.getRawDoc;
-	getContentInput.checked = config.getContent;
+	}
+
+	function updateProcessInBackground() {
+		processInBackgroundInput.checked = processInBackgroundInput.disabled = displayNotificationInput.checked || displayBannerInput.checked;
+	}
+
+	removeFramesInput = document.getElementById("removeFramesInput");
+	removeScriptsInput = document.getElementById("removeScriptsInput");
+	removeObjectsInput = document.getElementById("removeObjectsInput");
+	removeHiddenInput = document.getElementById("removeHiddenInput");
+	removeUnusedCSSRulesInput = document.getElementById("removeUnusedCSSRulesInput");
+	displayInContextMenuInput = document.getElementById("displayInContextMenuInput");
+	displayNotificationInput = document.getElementById("displayNotificationInput");
+	displayBannerInput = document.getElementById("displayBannerInput");
+	processInBackgroundInput = document.getElementById("processInBackgroundInput");
+	getRawDocInput = document.getElementById("getRawDocInput");
+	sendToPageArchiverInput = document.getElementById("sendToPageArchiverInput");
 	displayInContextMenuInput.addEventListener("click", bgPage.singlefile.refreshMenu);
+	displayNotificationInput.addEventListener("click", updateProcessInBackground, false);
+	displayBannerInput.addEventListener("click", updateProcessInBackground, false);
 	document.getElementById("resetButton").addEventListener("click", function() {
 		bgPage.singlefile.config.reset();
-		load();
-	});
+		refresh();
+	}, false);
 	addEventListener("click", function(event) {
 		var tooltip;
 		if (event.target.className == "question-mark") {
@@ -64,6 +85,8 @@
 			tooltip.style.display = tooltip.style.display == "block" ? "none" : "block";
 			event.preventDefault();
 		}
-	});
+	}, false);
+	document.getElementById("popupContent").onchange = update;
+	refresh();
 
 })();

+ 11 - 13
WebContent/ui/scripts/bg/ui.js

@@ -74,16 +74,6 @@
 			});
 	}
 
-	singlefile.ui.notifySavedPage = function(processed, filename) {
-		var notificationArchiving = webkitNotifications.createNotification(DEFAULT_ICON_PATH, "SingleFile", processed ? (filename + " is saved") : ("Error: "
-				+ filename + " cannot be saved"));
-		notificationArchiving.show();
-		if (processed)
-			setTimeout(function() {
-				notificationArchiving.cancel();
-			}, 3000);
-	};
-
 	singlefile.ui.notifyProcessInit = function(tabId) {
 		var tabData = {
 			id : tabId,
@@ -113,10 +103,18 @@
 		refreshBadge(tabId);
 	};
 
-	singlefile.ui.notifyProcessEnd = function(tabId, processingPagesCount) {
+	singlefile.ui.notifyProcessEnd = function(tabId, processingPagesCount, displayNotification, displayBanner, url, title) {
+		var params = encodeURIComponent(url) + "&" + encodeURIComponent(title);
+		if (displayNotification)
+			webkitNotifications.createHTMLNotification("notification.html?" + params).show();
+		if (displayBanner)
+			chrome.tabs.sendRequest(tabId, {
+				displayBanner : true,
+				url : chrome.extension.getURL("/pages/banner.html") + "?" + params
+			});
 		tabs[tabId].text = "OK";
 		delete tabs[tabId].processing;
-		badgeConfig.text = "" + (processingPagesCount || "");
+		badgeConfig.text = ("" + processingPagesCount || "");
 		if (!processingPagesCount) {
 			currentBarProgress = -1;
 			currentProgress = -1;
@@ -159,4 +157,4 @@
 		refreshBadge(tabId);
 	};
 
-})();
+})();

+ 33 - 0
WebContent/ui/scripts/content/banner.js

@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011 Gildas Lormeau
+ * contact : gildas.lormeau <at> gmail.com
+ * 
+ * This file is part of SingleFile.
+ *
+ *   SingleFile is free software: you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published by
+ *   the Free Software Foundation, either version 3 of the License, or
+ *   (at your option) any later version.
+ *
+ *   SingleFile is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with SingleFile.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function() {
+	var link = document.getElementById("link");
+	var params = location.search.substring(1).split("&");
+	var date = new Date();
+	var time = date.toISOString().split("T")[0] + " " + date.toLocaleTimeString();
+	link.href = decodeURIComponent(params[0]);
+	link.download = decodeURIComponent(params[1]) + " (" + time + ")" + ".htm";
+	link.onclick = document.getElementById("close").onclick = function() {
+		chrome.extension.sendRequest({
+			closeBanner : true
+		});
+	};
+})();

+ 34 - 1
WebContent/ui/scripts/content/content.js

@@ -48,6 +48,35 @@
 			document.body.removeChild(div);
 	}
 
+	function displayBanner(url) {
+		var frame = document.createElement("iframe");
+		frame.style.width = "100%";
+		frame.style.position = "fixed";
+		frame.style.top = "0px";
+		frame.style.left = "0px";
+		frame.style.borderWidth = "0px";
+		frame.style.borderBottomWidth = "1px";
+		frame.style.borderBottomStyle = "solid";
+		frame.style.borderBottomColor = "#b6bac0";
+		frame.style.zIndex = 2147483647;
+		frame.style["-webkit-transition"] = "height .5s ease-out";
+		frame.src = url;
+		frame.id = "singlefile-save-banner";
+		document.documentElement.style["-webkit-transition"] = "top .5s ease-out";
+		document.documentElement.style.position = "relative";
+		document.body.appendChild(frame);
+		frame.style.height = "0px";
+		frame.offsetLeft;
+		document.documentElement.style.top = "36px";
+		frame.style.height = "35px";
+	}
+
+	function closeBanner() {
+		document.documentElement.style["-webkit-transition-duration"] = "0s";
+		document.documentElement.style.top = "0px";
+		document.body.removeChild(document.getElementById("singlefile-save-banner"));
+	}
+
 	window.addEventListener("keyup", function(event) {
 		if (event.ctrlKey && event.shiftKey && event.keyCode == 83)
 			chrome.extension.sendRequest({});
@@ -59,6 +88,10 @@
 				processStart();
 			if (request.processEnd)
 				processEnd();
+			if (request.displayBanner)
+				displayBanner(request.url);
+			if (request.closeBanner)
+				closeBanner();
 		});
 
-})();
+})();