1 #title = "bk"
  2 #tooltip = "バックアップフォルダの専用領域に保存"
  3 #include "lib\sgc4jsee.jsee"
  4 
  5 /**
  6  * @fileOverview
  7  * 無題ドキュメント等を、バックアップフォルダの専用領域に保存します。<br />
  8  * <br />
  9  * [プロパティ]⇒[バックアップをバックアップ フォルダに保存]にチェックを入れた後、[バックアップ フォルダ]にパスを指定してください。<br />
 10  * バックアップ機能を使わない場合は、その後[バックアップをバックアップ フォルダに保存]のチェックを外してください。<br />
 11  * <br />
 12  * 最初に表示されるダイアログに入力する値で、以下のように機能が振り分けられます。
 13  * <dl>
 14  * 
 15  * <dt><p>■バックアップフォルダの専用領域に保存 ("s", "s"をダイアログに入力)</p></dt>
 16  * <dd><li><p>
 17  * 既定のバックアップフォルダに「EmEditorMacros_バックアップフォルダの専用領域に保存」というフォルダを専用領域として作成し、その中に"yyyyMMdd_HHmmss - "から始まるファイル名で保存します。<br />
 18  * 無題ドキュメントが対象なら、「専用領域 + "\yyyyMMdd_HHmmss." + [現在の設定のプロパティ]の[既定の拡張子]」という形式で保存します。<br />
 19  * 実際の動きとしては、新規タブを開いて、アクティブドキュメントの内容をそこにコピーして保存します。(そのためタブが1つ増える。)<br />
 20  * </p></li><li><p>
 21  * 既に保存されているファイルを保存する場合は、「専用領域 + "\yyyyMMdd_HHmmss - 元のファイル名.元の拡張子"」という形式で保存します。<br />
 22  * 専用領域内のファイルを再度保存する場合に限り、元のファイル名の日時部分を除去します。(例:"19990101_010101 - name.txt"⇒"19991231_020202 - name.txt")<br />
 23  * </p></li><li><p>
 24  * ファイルから検索した結果を保存する場合は、「専用領域 + "\yyyyMMdd_HHmmss - " + タイトルバーに表示されている文字列に近いファイル名 + ".txt"」という形式で保存します。
 25  * </p></li></dd>
 26  * 
 27  * <dt><p>■開いているファイルを残してバックアップフォルダの専用領域をゴミ箱へ移動 ("d", "d"をダイアログに入力)</p></dt>
 28  * <dd><li><p>
 29  * 現在開いているファイルだけを残して、このマクロの専用領域をゴミ箱に移動します。<br />
 30  * 実際の動きとしては、まず現在開いているファイルだけを格納した新領域を作成してから専用領域をゴミ箱に移動し、新領域を専用領域にリネームします。
 31  * </p></li></dd>
 32  * 
 33  * <dt><p>■バックアップフォルダの専用領域を開く ("o", "お"をダイアログに入力)</p></dt>
 34  * <dd><li><p>
 35  * このマクロが作った専用領域をExplorerで開きます。
 36  * </p></li></dd>
 37  * 
 38  * <dt><p>■バックアップフォルダの専用領域に名前を付けて保存 (上記以外の形式をダイアログに入力)</p></dt>
 39  * <dd><li><p>
 40  * 入力ダイアログに入力された文字列が上記に挙げた特殊な記号と完全に一致しない場合、<br />
 41  * 「専用領域 + "\yyyyMMdd_HHmmss - " + 入力された文字列 + "." + [現在の設定のプロパティ]の[既定の拡張子]」という形式で保存します。<br />
 42  * ファイル名に拡張子を付けた場合は、その拡張子で保存します。<br />
 43  * また、先頭に";"がある場合は日時情報を付加せずに「専用領域 + "\" + 先頭の";"を除いた入力された文字列 + "." + [現在の設定のプロパティ]の[既定の拡張子]」という形式で保存します。<br />
 44  * </p></li></dd>
 45  * 
 46  * </dl>
 47  * 
 48  * @author gecca from 雪月花 (http://setsugecca.org/)
 49  * @version 1.01 for EmEditor v10.0
 50  */
 51 
 52 (function () {
 53 	var logger = JseeUtil.getLogger(false, "バックアップフォルダの専用領域に保存.jsee");
 54 	
 55 	var SPECIAL_FOLDER_NAME = "EmEditorMacros_バックアップフォルダの専用領域に保存";
 56 	var DELIMITER = " - ";
 57 	var DELETE_SLEEP_MILLISECOND = 200;
 58 	var DELETE_SLEEP_COUNT = 20;
 59 	
 60 	// 名前を付けて保存するときに、日時情報を付加しないことを示す先頭のマーク
 61 	var mark = JseeUtil.getSnipIniObj("バックアップフォルダの専用領域に保存").mark || ";";
 62 	
 63 	var shell = new ActiveXObject("wscript.shell");
 64 	var fso = new ActiveXObject("scripting.filesystemobject");
 65 	
 66 	// 専用領域へのパス (末尾に\無し)
 67 	var backupSpecialPath = JseeUtil.getBackupDirPath() + SPECIAL_FOLDER_NAME;
 68 	// 削除しないファイル用フォルダへのパス (末尾に\無し)
 69 	var backupSpecialPathForUndeletedFiles = backupSpecialPath + "_bk";
 70 	
 71 	// 削除機能が途中で失敗した場合を判別し、復帰させる
 72 	(function() {
 73 		if(fso.FolderExists(backupSpecialPathForUndeletedFiles)) {
 74 			if(!fso.FolderExists(backupSpecialPath)) {
 75 				logger.log("削除しないファイル用フォルダはあるが本体がないので、マクロ終了後にゴミ箱へ移動されている。削除しないファイル用フォルダを本体にリネームして完了。");
 76 				fso.getFolder(backupSpecialPathForUndeletedFiles).Name = SPECIAL_FOLDER_NAME;
 77 				alert("前回の削除処理が正常に完了しました。");
 78 			} else {
 79 				logger.log("削除しないファイル用フォルダも本体もあるので、ゴミ箱への移動が失敗している。削除しないファイル用フォルダを削除。");
 80 				fso.DeleteFolder(backupSpecialPathForUndeletedFiles);
 81 				alert("前回の削除処理でゴミ箱への移動に失敗しました。\nファイルロックが行われていないか等を確認し、再度お試しください。");
 82 			}
 83 		}
 84 	})();
 85 	
 86 	var input = prompt("保存:s(s) | 保存:ファイル名 | 保存:" + mark + "ファイル名 | 削除:d(d) | 開く:o(お)", "s");
 87 	logger.log("プロンプト入力:" + input);
 88 	if(!input) {
 89 		logger.log("プロンプト入力なしのため終了");
 90 		return;
 91 	}
 92 	if(input == "d" || input == "d") {
 93 		del();
 94 	} else if(input == "o" || input == "お") {
 95 		open();
 96 	} else if(input == "s" || input == "s") {
 97 		save();
 98 	} else {
 99 		save(input);
100 	}
101 	
102 	return;
103 	
104 	function save(indicatedFileName) {
105 		logger.log("指定されたファイル名:" + indicatedFileName);
106 		
107 		if(!fso.FolderExists(backupSpecialPath)) {
108 			fso.CreateFolder(backupSpecialPath);
109 		}
110 		var backupPathAndDate = backupSpecialPath + "\\" + JseeUtil.dateFormat(new Date(), "yyyyMMdd_HHmmss");
111 		
112 		logger.log("document.Name:" + document.Name);
113 		logger.log("document.Path:" + document.Path);
114 		
115 		// ファイル名が指定された場合のファイルパスを取得する関数
116 		var getPathIfIndicatedFileName = function(indicatedFileName) {
117 			// 拡張子がなければ[既定の拡張子]を補完する関数
118 			var fillExt = function(fileName) {
119 				if(fileName.indexOf(".") < 0) {
120 					return fileName + "." + document.Config.FileSave.DefaultExtension;
121 				} else {
122 					return fileName;
123 				}
124 			};
125 			
126 			// 最初にマークがある場合は日時を付加しない
127 			if(new RegExp("^" + JseeUtil.quote(mark)).test(indicatedFileName)) {
128 				return backupSpecialPath + "\\" + fillExt(indicatedFileName.substring(mark.length));
129 			} else {
130 				return backupPathAndDate + DELIMITER + fillExt(indicatedFileName);
131 			}
132 		};
133 		
134 		if(document.Name) {
135 			if(document.Path.indexOf("\"") >= 0) {
136 				logger.log("検索結果ドキュメントとして判別されました。");
137 				
138 				var path = backupPathAndDate + DELIMITER + (document.Path.replace(/^"(.+)" .+$/, "“$1” ") + document.Name)
139 					.replace(/"/g, "”").replace(/\*/g, "*").replace(/\//g, "/").replace(/\\/g, "¥").replace(/:/g, ":");
140 				logger.log("保存パス:" + path);
141 				
142 				document.Save(path);
143 			} else {
144 				logger.log("保存済みドキュメントとして判別されました。");
145 				
146 				var path;
147 				if(indicatedFileName) {
148 					path = getPathIfIndicatedFileName(indicatedFileName);
149 				} else {
150 					if(new RegExp(SPECIAL_FOLDER_NAME + "\\\\\\d{8}_\\d{6}(" + DELIMITER + ")?([^\\\\]*?)(\.[^.]+)?$").test(document.FullName)) {
151 						logger.log("このマクロが作ったファイルと思われるため、元のファイル名から接頭辞を除去したものに接頭辞を追加。");
152 						if(RegExp.$1) {
153 							logger.log("元の区切り文字が検出されたので、「新しい日付+元の区切り文字+元の指定されたファイル名+元の指定された拡張子」をファイル名とする");
154 							path = backupPathAndDate + DELIMITER + RegExp.$2 + RegExp.$3;
155 						} else {
156 							logger.log("元の区切り文字が検出されないので、「新しい日付+元の拡張子」をファイル名とする");
157 							path = backupPathAndDate + RegExp.$3;
158 						}
159 					} else {
160 						logger.log("元のファイル名に接頭辞を追加。");
161 						path = backupPathAndDate + DELIMITER + document.Name;
162 					}
163 				}
164 				logger.log("保存パス:" + path);
165 				
166 				var allText = JseeUtil.getAllText();
167 				var encoding = document.Encoding;
168 				var configName = document.ConfigName;
169 				JseeUtil.newTab();
170 				document.selection.Text = allText;
171 				document.selection.StartOfDocument(false);
172 				document.ConfigName = configName;
173 				document.Encoding = encoding;
174 				try {
175 					editor.ActiveDocument.Save(path);
176 				} catch(e) {
177 					alert("保存に失敗しました。不正な文字が含まれている可能性があります。");
178 				}
179 			}
180 		} else {
181 			logger.log("無題ドキュメントとして判別されました。");
182 			
183 			var path;
184 			if(indicatedFileName) {
185 				path = getPathIfIndicatedFileName(indicatedFileName);
186 			} else {
187 				path = backupPathAndDate +  "." + document.Config.FileSave.DefaultExtension;
188 			}
189 			logger.log("保存パス:" + path);
190 			
191 			try {
192 				document.Save(path);
193 			} catch(e) {
194 				alert("保存に失敗しました。不正な文字が含まれている可能性があります。");
195 			}
196 		}
197 	}
198 	
199 	function del() {
200 		var openedDocs = [];
201 		
202 		for(var i=1;i<=editor.Documents.Count;i++) {
203 			if(editor.Documents.Item(i).FullName && fso.FileExists(editor.Documents.Item(i).FullName)) {
204 				if(logger.available()) {
205 					logger.log("開かれているバックアップフォルダのファイル :" + fso.getFile(editor.Documents.Item(i).FullName).shortPath);
206 				}
207 				openedDocs.push(fso.getFile(editor.Documents.Item(i).FullName).shortPath);
208 			}
209 		}
210 		
211 		if(!fso.FolderExists(backupSpecialPath)) {
212 			alert("このマクロがバックアップフォルダに作成した専用領域は現在存在しません。");
213 			return;
214 		}
215 		
216 		if(!confirm("現在の専用領域をゴミ箱に移動し、\n現在開いているファイルだけを含む専用領域を作成します。\n\n"
217 				+ "削除対象ファイルがロックされていたり、ゴミ箱への移動に時間がかかり過ぎた場合、"
218 				+ "最大で" + (DELETE_SLEEP_MILLISECOND * DELETE_SLEEP_COUNT / 1000) + "秒間EmEditorが待機状態となります。\n\n"
219 				+ "よろしいですか?")) {
220 			return;
221 		}
222 		
223 		logger.log("削除しないファイル用フォルダの作成");
224 		fso.CreateFolder(backupSpecialPathForUndeletedFiles);
225 		
226 		logger.log("開かれているドキュメントを、削除しないファイル用フォルダへコピー");
227 		var files = JseeUtil.col2arr(fso.getFolder(backupSpecialPath).Files);
228 		for(var i=0;i<files.length;i++) {
229 			var file = files[i];
230 			logger.log("\t開かれたドキュメントかどうかチェック");
231 			if(logger.available()) {
232 				logger.log("\t対象ファイル:" + fso.getFile(file).shortPath);
233 			}
234 			if(JseeUtil.contains(openedDocs, fso.getFile(file).shortPath)) {
235 				logger.log("\t\t開かれたドキュメントであると判断して、削除しないファイル用フォルダへコピー");
236 				fso.CopyFile(file, backupSpecialPathForUndeletedFiles + "\\");
237 			}
238 		}
239 		
240 		logger.log("削除対象がなければロールバック");
241 		if(JseeUtil.col2arr(fso.getFolder(backupSpecialPath).Files).length == JseeUtil.col2arr(fso.getFolder(backupSpecialPathForUndeletedFiles).Files).length) {
242 			logger.log("専用領域のファイル数と削除しないファイル用フォルダのファイル数が同じなので、削除しないファイル用フォルダを削除");
243 			alert("専用領域にあるファイルは全て開かれています。");
244 			fso.DeleteFolder(backupSpecialPathForUndeletedFiles);
245 			return;
246 		}
247 		
248 		logger.log("作業用スクリプトを作成して実行");
249 		var tempWsh = JseeUtil.getTempDirPath() + "EmEditorMacros_バックアップフォルダに保存.js";
250 		
251 		var wshContent
252 			= "new ActiveXObject(\"Shell.Application\").NameSpace(10).MoveHere(\"" + (backupSpecialPath + "\\").replace(/\\/g, "\\\\") + "\");\n"
253 			+ "\n"
254 			+ "for(var i=0;i<" + DELETE_SLEEP_COUNT + ";i++) {\n"
255 			+ "	WScript.Sleep(" + DELETE_SLEEP_MILLISECOND + ");\n"
256 			+ "	var fso = new ActiveXObject(\"Scripting.FileSystemObject\")\n"
257 			+ "	if(!fso.FolderExists(\"" + backupSpecialPath.replace(/\\/g, "\\\\") + "\")) {\n"
258 			+ "		WScript.Quit(0);\n"
259 			+ "	}\n"
260 			+ "}\n"
261 			+ "\n"
262 			+ "WScript.Quit(1);\n"
263 		;
264 		logger.log("↓作業用スクリプトの内容↓\n\n" + wshContent);
265 		logger.log("↑作業用スクリプトの内容↑");
266 		
267 		JseeUtil.writeFile(tempWsh, wshContent);
268 		Sleep(200);
269 		
270 		if(logger.available()) {
271 			logger.log("臨時WSH実行パス:wscript \"" + tempWsh + "\"");
272 		}
273 		var execed = shell.exec("wscript \"" + tempWsh + "\"");
274 		
275 		var isRightExec = false;
276 		for(var i=0;i<DELETE_SLEEP_COUNT;i++) {
277 			if(execed.status != 0) {
278 				isRightExec = true;
279 				break;
280 			}
281 			Sleep(DELETE_SLEEP_MILLISECOND);
282 		}
283 		
284 		logger.log("isRightExec:" + isRightExec);
285 		logger.log("execed.ExitCode:" + execed.ExitCode);
286 		if(isRightExec && execed.ExitCode == 0) {
287 			logger.log("スクリプトが正常に終了");
288 			fso.getFolder(backupSpecialPathForUndeletedFiles).Name = SPECIAL_FOLDER_NAME;
289 			alert("処理が完了しました。");
290 		} else {
291 			shell.Popup("ファイルロックされている、またはゴミ箱への移動に時間がかかり過ぎたため、処理を中断しました。\nゴミ箱への移動に失敗した可能性があります。\n\n再度マクロを実行してください。");
292 		}
293 		fso.DeleteFile(tempWsh);
294 	}
295 	
296 	function open() {
297 		if(fso.FolderExists(backupSpecialPath)) {
298 			shell.Run("explorer " + backupSpecialPath);
299 		} else {
300 			alert("専用領域は現在存在しません。\nバックアップフォルダを開きます。");
301 			shell.Run("explorer " + JseeUtil.getBackupDirPath());
302 		}
303 	}
304 })();
305