| <apex:component > | 
| <script type="text/javascript"> | 
| ; | 
| 'use strict'; | 
| angular.module('alImageService', []) | 
|   | 
| // 画像情報を保持する | 
| .factory('alPhotos', ['$q', 'svcSettings', 'alImageUtil', function($q, svcSettings, alImageUtil) { | 
|   var photos =[]; | 
|    | 
|   | 
|   var getDecimalFormat = function(val) { | 
|     if (!angular.isArray(val) || val.length != 3) return 0; | 
|     return val[0].numerator/val[0].denominator | 
|           +val[1].numerator/(val[1].denominator * 60) | 
|           +val[2].numerator/(val[2].denominator * 3600); | 
|   } | 
|   | 
|   // 元ファイルの画像の圧縮率 と相応する 設定されたファイルサイズ上限値における 長辺のピクセル数 | 
|   var getLongSidePixcels = function(org_size, org_x, org_y, maxSize) { | 
|     // alert(org_size + ' ' + org_x + ' ' + org_y + ' ' + maxSize); | 
|     var ratio =  (org_x * org_y)/org_size         // 元ファイルの画像の圧縮率 | 
|     // alert('ratio : ' + ratio); | 
|     var result = Math.sqrt((maxSize * ratio * 4) /3);    // 元ファイルの画像の圧縮率 と相応する長辺のピクセル数 | 
|     // alert('result : ' + result); | 
|     return result; | 
|   } | 
|   | 
|   // dataUrl から 縮小した | 
|   // File から所定のデータを取得 EXIFデータも読む | 
|   // | 
|   var createFileObjctEx = function(imageFile, maxSize, longSidePixcel, jpegQuality) { | 
|     var defer = $q.defer(); | 
|     var file = {"file": null,     //imageFile,      // オリジナルの File | 
|               "blob": null,             // 縮小したBlob | 
|               "data": null,             // 縮小した dataUrl の予定 | 
|               "name": imageFile.name, | 
|               "type": imageFile.type, | 
|               "org_size": imageFile.size + 400000,    // iPhoneだと ファイルサイズが実際より小さい値になってるので、これで | 
|               "height": "*",  // ピクセル数 | 
|               "width": "*",   // | 
|               "yoko": true,   // 横? | 
|               "position": {"lat":null, "lng":null}, | 
|               "exif": null}; // EXIF文字列 | 
|     var reader = new FileReader(); | 
|     reader.onload = function () { | 
|       file.data = reader.result; | 
|       var image = new Image(); | 
|       image.onload = function() { | 
|           EXIF.getData(image, function() { | 
|             file.exif = EXIF.pretty(this); | 
|             // file.exif = JSON.parse(EXIF.pretty(this)); | 
|             // EXIFがない画像ファイルなら、480☓480 | 
|             // 緯度:35度38分45秒54 経度:139度42分35秒97 | 
|             var longSide = longSidePixcel; | 
|             var org_x = EXIF.getTag(this, "PixelXDimension"); | 
|             var org_y = EXIF.getTag(this, "PixelYDimension"); | 
|             if (angular.isDefined(org_x) && angular.isDefined(org_y)) { | 
|               longSide = getLongSidePixcels(file.org_size, org_x, org_y, maxSize); | 
|             } | 
|             file.position.lat = file.exif.length == 0 ? 0 : getDecimalFormat( EXIF.getTag(this, "GPSLatitude")); | 
|             file.position.lng = file.exif.length == 0 ? 0 : getDecimalFormat( EXIF.getTag(this, "GPSLongitude")); | 
|             file.yoko = file.width > file.height; | 
|             alImageUtil.getResizedData(image.src, longSide, jpegQuality, function(res) { | 
|               file.blob = res.blob; | 
|               file.data = res.data; | 
|               file.height = res.height; | 
|               file.width = res.width; | 
|               defer.resolve(file); | 
|             }); | 
|           }); | 
|       }; | 
|       image.src = reader.result; | 
|     }; | 
|     reader.readAsDataURL(imageFile); | 
|     return defer.promise; | 
|   }; | 
|    | 
|   return { | 
|     all: function() { | 
|       return photos; | 
|     }, | 
|     get: function(index) { | 
|       if (index >=0 && index < photos.length) | 
|         return photos[index]; | 
|       else | 
|         return null; | 
|   | 
|     }, | 
|     // 写真の削除 | 
|     remove: function(photo) { | 
|        photos.splice(photos.indexOf(photo), 1); | 
|     }, | 
|     // 写真の追加 | 
|     appendFile: function(file, config, callbackSuccess, callbackFailure) { | 
|       // ファイル情報の取得、縮小して、保持するオブジェクトを作成 | 
|       createFileObjctEx(file, config.maxFileSize, config.longSidePixcel, config.jpegQuality).then(function(res) { | 
|         photos.push(res); | 
|         callbackSuccess(res); | 
|       }, | 
|       function() { | 
|         callbackFailure(null); | 
|       }); | 
|     }, | 
|   | 
|     clear: function() { | 
|       photos.splice(0, photos.length); | 
|     }, | 
|     size: function() { | 
|       return photos.length; | 
|     } | 
|   | 
|   }; | 
| }]) | 
| // ローカルセッション使うよう | 
| .factory('svLocalstorage', ['$window', function($window) { | 
|   return { | 
|     set: function(key, value) { | 
|       $window.localStorage['sv-'+key] = value; | 
|     }, | 
|     get: function(key, defaultValue) { | 
|       return $window.localStorage['sv-'+key] || defaultValue; | 
|     }, | 
|     setObject: function(key, value) { | 
|       $window.localStorage['sv-'+key] = JSON.stringify(value); | 
|     }, | 
|     getObject: function(key) { | 
|       return JSON.parse($window.localStorage['sv-'+key] || '{}'); | 
|     } | 
|   } | 
| }]) | 
| // 設定の取得・保存 | 
| .factory('svcSettings', ['$window', function($window) { | 
|   return { | 
|     set: function(value) { | 
|       $window.localStorage['sv-settings'] = JSON.stringify(value); | 
|     }, | 
|     get: function() { | 
|       return JSON.parse($window.localStorage['sv-settings'] || | 
|                     // 設定のデフォルト値 | 
|                     '{ "doubleSide": true, ' +      // 初期設定 撮影ごと変更可能 | 
|                       ' "viewMode": "list", ' + | 
|                       ' "imageSize": "600", ' +     // 長辺のピクセル数 | 
|                       ' "repeatExchangeDate": true, ' + | 
|                       ' "repeatMemo": true, ' + | 
|                       ' "rememberListName": true, ' + | 
|                       ' "previousListName": "", ' + | 
|                       ' "freehandMemo": false, ' + | 
|                       ' "frontOnly": false, ' +     // | 
|                       ' "geoLocation": true}'); | 
|     } | 
|   } | 
| }]) | 
|   | 
| .factory('alImageUtil', ['$q', function($q) { | 
|   return { | 
|     createBlobFromDataUrl: createBlobFromDataUrl, | 
|     getResizedData: getResizedData, | 
|   }; | 
|   | 
|   function createBlobFromDataUrl(dataurl, type, name) { | 
|     var barr, bin, i, len, type = type || 'image/jpeg'; | 
|     bin = atob(dataurl.split("base64,")[1]); | 
|     len = bin.length; | 
|     barr = new Uint8Array(len); | 
|     i = 0; | 
|     while (i < len) { | 
|       barr[i] = bin.charCodeAt(i); | 
|       i++; | 
|     } | 
|     return new Blob([barr], { | 
|       // name: name, | 
|       type: type | 
|     }); | 
|   } | 
|   | 
|   function getResizedData(data, size, jpegQuality, callbackSuccess, callbackFailure) { | 
|     var result ={"blob": null, "data":null, "width":0, "height": 0}; | 
|     var maxWidth = size; | 
|     var maxHeight = size; | 
|     var img = new Image(); | 
|   | 
|     img.onload = function() { | 
|   | 
|         var iw = img.naturalWidth, ih = img.naturalHeight; | 
|         var width = iw, height = ih; | 
|   | 
|         var orientation; | 
|   | 
|         // JPEGの場合には、EXIFからOrientation(回転)情報を取得 | 
|         if (data.split(',')[0].match('jpeg')) { | 
|             orientation = getOrientation(data); | 
|         } | 
|         // JPEG以外や、JPEGでもEXIFが無い場合などには、標準の値に設定 | 
|         orientation = orientation || 1; | 
|   | 
|         // 90度回転など、縦横が入れ替わる場合には事前に最大幅、高さを入れ替えておく | 
|         if (orientation > 4) { | 
|             var tmpMaxWidth = maxWidth; | 
|             maxWidth = maxHeight; | 
|             maxHeight = tmpMaxWidth; | 
|         } | 
|   | 
|         if(width > maxWidth || height > maxHeight) { | 
|             var ratio = width/maxWidth; | 
|             if(ratio <= height/maxHeight) { | 
|                 ratio = height/maxHeight; | 
|             } | 
|             width = Math.floor(img.width/ratio); | 
|             height = Math.floor(img.height/ratio); | 
|         } | 
|   | 
|         var canvas = $('<canvas>'); | 
|         var ctx = canvas[0].getContext('2d'); | 
|         ctx.save(); | 
|   | 
|         // EXIFのOrientation情報からCanvasを回転させておく | 
|         transformCoordinate(canvas, width, height, orientation); | 
|   | 
|         // iPhoneのサブサンプリング問題の回避 | 
|         // see http://d.hatena.ne.jp/shinichitomita/20120927/1348726674 | 
|         var subsampled = detectSubsampling(img); | 
|         if (subsampled) { | 
|             iw /= 2; | 
|             ih /= 2; | 
|         } | 
|         var d = 1024; // size of tiling canvas | 
|         var tmpCanvas = $('<canvas>'); | 
|         tmpCanvas[0].width = tmpCanvas[0].height = d; | 
|         var tmpCtx = tmpCanvas[0].getContext('2d'); | 
|         var vertSquashRatio = detectVerticalSquash(img, iw, ih); | 
|         var dw = Math.ceil(d * width / iw); | 
|         var dh = Math.ceil(d * height / ih / vertSquashRatio); | 
|         var sy = 0; | 
|         var dy = 0; | 
|         while (sy < ih) { | 
|             var sx = 0; | 
|             var dx = 0; | 
|             while (sx < iw) { | 
|                 tmpCtx.clearRect(0, 0, d, d); | 
|                 tmpCtx.drawImage(img, -sx, -sy); | 
|                 ctx.drawImage(tmpCanvas[0], 0, 0, d, d, dx, dy, dw, dh); | 
|                 sx += d; | 
|                 dx += dw; | 
|             } | 
|             sy += d; | 
|             dy += dh; | 
|         } | 
|         ctx.restore(); | 
|         tmpCanvas = tmpCtx = null; | 
|   | 
|         // プレビューするために<img>用のDataURLを作成 | 
|         // (スマホなどの狭小画面でも画像の全体図が見れるように、解像度を保ったたま縮小表示したいので) | 
|         var displaySrc = ctx.canvas.toDataURL('image/jpeg', jpegQuality/10);      // 2016.07.07  JPEG品質は設定から指定 | 
|   | 
|         // FormDataに縮小後の画像データを追加する | 
|         // Blob形式にすることで、サーバ側は従来のままのコードで対応可能 | 
|         var blob = dataURLtoBlob(displaySrc); | 
|         result.data = displaySrc; | 
|         result.blob = blob; | 
|         result.width = width; | 
|         result.height = height; | 
|         callbackSuccess(result); | 
|     } | 
|     img.src = data; | 
|   | 
|   | 
|   // JPEGのEXIFからOrientationのみを取得する | 
|   var getOrientation = function(imgDataURL) { | 
|       var byteString = atob(imgDataURL.split(',')[1]); | 
|       var orientaion = byteStringToOrientation(byteString); | 
|       return orientaion; | 
|   | 
|       function byteStringToOrientation(img){ | 
|           var head = 0; | 
|           var orientation; | 
|           while (1){ | 
|               if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 218) {break;} | 
|               if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 216) { | 
|                   head += 2; | 
|               } | 
|               else { | 
|                   var length = img.charCodeAt(head + 2) * 256 + img.charCodeAt(head + 3); | 
|                   var endPoint = head + length + 2; | 
|                   if (img.charCodeAt(head) == 255 & img.charCodeAt(head + 1) == 225) { | 
|                       var segment = img.slice(head, endPoint); | 
|                       var bigEndian = segment.charCodeAt(10) == 77; | 
|                       if (bigEndian) { | 
|                           var count = segment.charCodeAt(18) * 256 + segment.charCodeAt(19); | 
|                       } else { | 
|                           var count = segment.charCodeAt(18) + segment.charCodeAt(19) * 256; | 
|                       } | 
|                       for (var i=0;i<count;i++){ | 
|                           var field = segment.slice(20 + 12 * i, 32 + 12 * i); | 
|                           if ((bigEndian && field.charCodeAt(1) == 18) || (!bigEndian && field.charCodeAt(0) == 18)) { | 
|                               orientation = bigEndian ? field.charCodeAt(9) : field.charCodeAt(8); | 
|                           } | 
|                       } | 
|                       break; | 
|                   } | 
|                   head = endPoint; | 
|               } | 
|               if (head > img.length){break;} | 
|           } | 
|           return orientation; | 
|       } | 
|     } | 
|   | 
|     // iPhoneのサブサンプリングを検出 | 
|     var detectSubsampling = function(img) { | 
|         var iw = img.naturalWidth, ih = img.naturalHeight; | 
|         if (iw * ih > 1024 * 1024) { | 
|             var canvas = $('<canvas>'); | 
|             canvas[0].width = canvas[0].height = 1; | 
|             var ctx = canvas[0].getContext('2d'); | 
|             ctx.drawImage(img, -iw + 1, 0); | 
|             return ctx.getImageData(0, 0, 1, 1).data[3] === 0; | 
|         } else { | 
|             return false; | 
|         } | 
|     } | 
|   | 
|     // iPhoneの縦画像でひしゃげて表示される問題 | 
|     var detectVerticalSquash = function (img, iw, ih) { | 
|         var canvas = $('<canvas>'); | 
|         canvas[0].width = 1; | 
|         canvas[0].height = ih; | 
|         var ctx = canvas[0].getContext('2d'); | 
|         ctx.drawImage(img, 0, 0); | 
|         var data = ctx.getImageData(0, 0, 1, ih).data; | 
|         var sy = 0; | 
|         var ey = ih; | 
|         var py = ih; | 
|         while (py > sy) { | 
|             var alpha = data[(py - 1) * 4 + 3]; | 
|             if (alpha === 0) { | 
|                 ey = py; | 
|             } else { | 
|                 sy = py; | 
|             } | 
|             py = (ey + sy) >> 1; | 
|         } | 
|         var ratio = (py / ih); | 
|         return (ratio===0)?1:ratio; | 
|     } | 
|   | 
|   | 
|     var transformCoordinate = function (canvas, width, height, orientation) { | 
|         if (orientation > 4) { | 
|             canvas[0].width = height; | 
|             canvas[0].height = width; | 
|         } else { | 
|             canvas[0].width = width; | 
|             canvas[0].height = height; | 
|         } | 
|         var ctx = canvas[0].getContext('2d'); | 
|         switch (orientation) { | 
|             case 2: | 
|                 // horizontal flip | 
|                 ctx.translate(width, 0); | 
|                 ctx.scale(-1, 1); | 
|                 break; | 
|             case 3: | 
|                 // 180 rotate left | 
|                 ctx.translate(width, height); | 
|                 ctx.rotate(Math.PI); | 
|                 break; | 
|             case 4: | 
|                 // vertical flip | 
|                 ctx.translate(0, height); | 
|                 ctx.scale(1, -1); | 
|                 break; | 
|             case 5: | 
|                 // vertical flip + 90 rotate right | 
|                 ctx.rotate(0.5 * Math.PI); | 
|                 ctx.scale(1, -1); | 
|                 break; | 
|             case 6: | 
|                 // 90 rotate right | 
|                 ctx.rotate(0.5 * Math.PI); | 
|                 ctx.translate(0, -height); | 
|                 break; | 
|             case 7: | 
|                 // horizontal flip + 90 rotate right | 
|                 ctx.rotate(0.5 * Math.PI); | 
|                 ctx.translate(width, -height); | 
|                 ctx.scale(-1, 1); | 
|                 break; | 
|             case 8: | 
|                 // 90 rotate left | 
|                 ctx.rotate(-0.5 * Math.PI); | 
|                 ctx.translate(-width, 0); | 
|                 break; | 
|             default: | 
|                 break; | 
|         } | 
|     } | 
|   | 
|     var dataURLtoArrayBuffer = function(data) { | 
|         var byteString = atob(data.split(',')[1]); | 
|         var ab = new ArrayBuffer(byteString.length); | 
|         var ia = new Uint8Array(ab); | 
|         for (var i = 0; i < byteString.length; i++) { | 
|             ia[i] = byteString.charCodeAt(i); | 
|         } | 
|         return ab | 
|     } | 
|   | 
|     var dataURLtoBlob = function (data) { | 
|         var mimeString = data.split(',')[0].split(':')[1].split(';')[0]; | 
|         var ab = dataURLtoArrayBuffer(data); | 
|         var bb = (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder); | 
|         if (bb) { | 
|             bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder)(); | 
|             bb.append(ab); | 
|             return bb.getBlob(mimeString); | 
|         } else { | 
|             bb = new Blob([ab], { | 
|                     'type': (mimeString) | 
|             }); | 
|             return bb; | 
|         } | 
|     } | 
| // バイナリ化した画像をPOSTで送る関数 | 
| // http://blog.sarabande.jp/post/30694191998 | 
|   var sendImageBinary = function(blob) { | 
|     var formData = new FormData(); | 
|     formData.append('acceptImage', blob); | 
|       $.ajax({ | 
|       type: 'POST', | 
|       url: 'image-accept2.php', | 
|       data: formData, | 
|       contentType: false, | 
|       processData: false, | 
|       success:function(date, dataType){ | 
|         var $img = $('img'); | 
|         var imgSrc = $img.attr('src'); | 
|         $img.attr('src', ""); | 
|         $img.attr('src', imgSrc + '?' + (new Date())*1); | 
|       }, | 
|       error: function(XMLHttpRequest, textStatus, errorThrown) { | 
|       } | 
|     }); | 
|   }; | 
|   } | 
| // 引数のBase64の文字列をBlob形式にしている | 
| var base64ToBlob = function(base64){ | 
|   var base64Data = base64.split(',')[1], // Data URLからBase64のデータ部分のみを取得 | 
|     data = window.atob(base64Data), // base64形式の文字列をデコード | 
|     buff = new ArrayBuffer(data.length), | 
|     arr = new Uint8Array(buff), | 
|     blob, i, dataLen; | 
|   | 
|   // blobの生成 | 
|   for( i = 0, dataLen = data.length; i < dataLen; i++){ | 
|     arr[i] = data.charCodeAt(i); | 
|   } | 
|   blob = new Blob([arr], {type: 'image/png'}); | 
|   return blob; | 
| } | 
| }]) | 
|   | 
| // モーダル ダイアログ用 | 
| .factory('alModal', ['$uibModal', '$log', '$q', function($uibModal, $log, $q) { | 
|   | 
|  return { | 
|   openLoading : openLoading,    // ファイル開くとき用 | 
|   closeLoading : closeLoading,  // ファイル開くとき用のを閉じる | 
|   openConfirm : openConfirm,    // 送信確認 | 
|   openProgress : openProgress,   // 送信中 | 
|   openWarning : openWarning,    // エラー|警告 表示 | 
|   openImage : openImage | 
|  } | 
|   | 
|   var modalLoadingInstance = null; | 
|   | 
|   function openLoading() { | 
|       modalLoadingInstance = $uibModal.open({ | 
|         animation: false, | 
|         template: ' ', | 
|         // templateUrl: ', | 
|         // windowClass: 'width: 100px; opacity:0', | 
|         // windowClass: 'border-width: 0px;', | 
|         windowTemplateUrl : 'loadingWindow.html', | 
|         // backdropClass: "background-image: url('images/ajax-loader.gif')", | 
|         size: 'sm', | 
|         backdrop: true, | 
|     }); | 
|     return modalLoadingInstance; | 
|   } | 
|   | 
|   function closeLoading() { | 
|     if (modalLoadingInstance) { | 
|       modalLoadingInstance.close(); | 
|       modalLoadingInstance = null; | 
|     } | 
|   } | 
|   | 
|   // 処理実行 確認用 | 
|   function openConfirm(scope, templateUrl) { | 
|     var defer = $q.defer(); | 
|     var modalInstance = $uibModal.open({ | 
|       scope: scope, | 
|       animation: true, | 
|       backdrop: 'static', | 
|       templateUrl: templateUrl, | 
|       // controller: 'ModalInstanceCtrl', | 
|       size: 'sm', | 
|     }); | 
|   | 
|     // modalInstance.result.then(function(res) { | 
|     modalInstance.result.then(function() { | 
|       $log.info('Confirm OK at: ' + new Date()); | 
|       // scope.status.showLog = res; | 
|       modalInstance = null; | 
|       defer.resolve('OK'); | 
|     }, function () { | 
|       $log.info('Confirm dismissed at: ' + new Date()); | 
|       modalInstance = null; | 
|       defer.reject('Cancel'); | 
|     }); | 
|     return defer.promise; | 
|   } | 
|   | 
|   // 送信中+結果表示 | 
|   function openProgress(scope) { | 
|     var defer = $q.defer(); | 
|     var modalInstance = $uibModal.open({ | 
|       scope: scope, | 
|       animation: true, | 
|       backdrop: 'static', | 
|       templateUrl: 'uploading.html', | 
|       controller: 'redirectCtrl', | 
|       size: 'lg', | 
|     }); | 
|   | 
|     modalInstance.result.then(function () { | 
|       $log.info('Upload completed at: ' + new Date()); | 
|       modalInstance = null; | 
|       defer.resolve('success'); | 
|     }); | 
|     return defer.promise; | 
|   } | 
|   // 警告表示 | 
|   function openWarning(text) { | 
|     var defer = $q.defer(); | 
|     var modalInstance = $uibModal.open({ | 
|       animation: true | 
|       , backdrop: 'static' | 
|       , template: '<div class="modal-body">' | 
|                 + '<p><i class="fa fa-exclamation-circle fa-lg" style="color:#2aabd2;"></i> ' | 
|                 + text | 
|                 + '</p></div>' | 
|                 +'<div class="modal-footer" style="background-color :#f8f8ff">' | 
|                 +'<button class="pull-right btn btn-info col-xs-4" ng-click="$close()">OK</button>' | 
|                 +'</div>' | 
|       , size: 'sm' | 
|     }); | 
|     modalInstance.result.then(function () { | 
|       modalInstance = null; | 
|       defer.resolve('success'); | 
|     }, function () { | 
|       modalInstance = null; | 
|       defer.reject('falt'); | 
|     }); | 
|     return defer.promise; | 
|   } | 
|   | 
|   function openImage(images, index) { | 
|     var images = images | 
|     var modalInstance = $uibModal.open({ | 
|       animation: true, | 
|       backdrop: true, | 
|       templateUrl: 'imageWindow.html', | 
|       controller: ['$scope', function ($scope) { | 
|           $scope.images = Lightbox; | 
|           Lightbox.keyboardNavEnabled = true; | 
|       }], | 
|       size: 'lg', | 
|     }); | 
|   | 
|     $scope.preveImage = function() { | 
|   | 
|     } | 
|   } | 
|   | 
| }]) | 
|   | 
| // 送信履歴用 | 
| .factory('alHistory', ['$window', function($window) { | 
|   return { | 
|     getTemplate: getTemplate | 
|     , get: get | 
|     , append: append | 
|     , clear: clear | 
|     , getDailySortedDesc: getDailySortedDesc | 
|     , getDailyBlocked: getDailyBlocked | 
|   } | 
|   function getTemplate(latLng) { | 
|     var d = new Date(); | 
|     var log = { | 
|       'date': d.getFullYear() + '/' + ('0' + (d.getMonth() + 1)).slice(-2) + '/' +('0' + d.getDate()).slice(-2) + ' ' + ['日','月','火','水','木','金','土'][d.getDay()] | 
|       , 'time': ('0' + d.getHours()).slice(-2) +':' + ('0' + d.getMinutes()).slice(-2) + ':' + ('0' + d.getSeconds()).slice(-2) | 
|       , 'location': {'lat': latLng.lat, 'lng': latLng.lng} | 
|       , 'name': null | 
|       , 'landId': null | 
|       , 'landNumber': null | 
|       , 'attachmentIds': [] | 
|       , 'success': false | 
|       };    // 画像数 | 
|     return log; | 
|   } | 
|   | 
|   function get() { | 
|     return $window.localStorage['al-history'] ? JSON.parse($window.localStorage['al-history']) : []; | 
|   } | 
|   // getObject: function() { | 
|   //   return JSON.parse($window.localStorage['al-history'] || '{}'); | 
|   // }, | 
|   function append(log) { | 
|     var logs = $window.localStorage['al-history'] ? JSON.parse($window.localStorage['al-history']) : []; | 
|     // 100 件に達したら、1件目を削除 | 
|     if (logs.length > 99) { | 
|       logs.splice(0, 1); | 
|     } | 
|     logs.push(log); | 
|     $window.localStorage['al-history'] = JSON.stringify(logs); | 
|   } | 
|   function clear() { | 
|     window.localStorage.removeItem('al-history'); | 
|   } | 
|   function getDailySortedDesc() { | 
|     var logs = $window.localStorage['al-history'] ? JSON.parse($window.localStorage['al-history']) : []; | 
|     // 降順にソート | 
|     logs.sort(function(a,b) { | 
|       if (b.date === a.date) { | 
|         return (b.time === a.time ? 0 : (b.time > a.time ? 1 : -1)); | 
|       } | 
|       else { | 
|         return (b.date > a.date ? 1 : -1); | 
|       } | 
|     }); | 
|     return logs; | 
|   } | 
|   function getDailyBlocked() { | 
|     var logs = $window.localStorage['al-history'] ? JSON.parse($window.localStorage['al-history']) : []; | 
|     // 降順にソート | 
|     if (logs.length === 0) return []; | 
|     logs.sort(function(a,b) { | 
|       if (b.date === a.date) { | 
|         return (b.time === a.time ? 0 : (b.time > a.time ? 1 : -1)); | 
|       } | 
|       else { | 
|         return (b.date > a.date ? 1 : -1); | 
|       } | 
|     }); | 
|     //  日単位のオブジェクトの配列を作成 | 
|     var result =[]; | 
|     var date = ""; | 
|     for (var n = 0; n<logs.length; n++) { | 
|       if (date !== logs[n].date) { | 
|         var day = {"date": logs[n].date, "actions":[logs[n]]}; | 
|         result.push(day); | 
|         date = logs[n].date; | 
|       } | 
|       else { | 
|         result[result.length-1].actions.push(logs[n]); | 
|       } | 
|     } | 
|     return result; | 
|   } | 
| }]) | 
| // GPS使用 | 
| .factory('alGps', ['$q', '$log', function($q, $log) { | 
|   return { | 
|     getCurrentLocation : getCurrentLocation, | 
|     getCurrentLocationPromise : getCurrentLocationPromise | 
|   } | 
|   function getCurrentLocation(callbackSuccess, callbackFailure) { | 
|     if (navigator.geolocation) { | 
|       navigator.geolocation.getCurrentPosition( | 
|         function(position) { | 
|           var res = {"lat": null, "lng": null};     // これで保存するので名前に注意 | 
|           res["lat"] = position.coords.latitude; | 
|           res["lng"] = position.coords.longitude; | 
|           callbackSuccess(res); | 
|         }, | 
|         function(err) { | 
|           var res = 'ERROR(' + err.code + '): ' + err.message; | 
|           $log.info([{"text": res}]); | 
|           callbackFailure(res); | 
|       }); | 
|     } | 
|     else { | 
|       callbackFailure([{"text": 'geolocation not supported.'}]); | 
|     } | 
|   } | 
|   function getCurrentLocationPromise() { | 
|     var defer = $q.defer(); | 
|     if (navigator.geolocation) { | 
|       navigator.geolocation.getCurrentPosition( | 
|         function(position) { | 
|           var res = {"lat": null, "lng": null};     // これで保存するので名前に注意 | 
|           res.lat = position.coords.latitude; | 
|           res.lng = position.coords.longitude; | 
|           defer.resolve(res); | 
|         }, | 
|         function(err) { | 
|           $log.error('ERROR(' + err.code + '): ' + err.message); | 
|           defer.reject(); | 
|       }); | 
|     } | 
|     return defer.promise; | 
|   } | 
|   | 
| }]) | 
| ; | 
|   | 
| </script> | 
| </apex:component> |