commit cb344b8069c69b8dd8d017fd225b3ffe9de2f01a Author: Dym Sohin Date: Wed Oct 4 20:39:05 2023 +0200 re-init diff --git a/index.html b/index.html new file mode 100644 index 0000000..71feb98 --- /dev/null +++ b/index.html @@ -0,0 +1,45 @@ + + +Git.io + + + + + + + + + + + + + + + +
+ + +
+ +
+ + + +
+ + + + + + + + + + + diff --git a/manifest.webapp b/manifest.webapp new file mode 100644 index 0000000..e0d81d7 --- /dev/null +++ b/manifest.webapp @@ -0,0 +1,11 @@ +{ "name": "Git.io Addon" +, "description": "git.io browser extension with support for custom URLs and shrt-history" +, "launch_path": "./" +, "default_locale": "en" +, "icons": + { "500": "icon.png" } +, "developer": + { "name": "Dym Sohin" + , "url": "https://dym.sh" + } +} diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000..a5c47c4 Binary files /dev/null and b/screenshot.png differ diff --git a/script.js b/script.js new file mode 100644 index 0000000..ebea41b --- /dev/null +++ b/script.js @@ -0,0 +1,252 @@ +var GitIO = function ( ) + { + var API_ENDPOINT = 'http://git.io/' + + this.invoke = function ( command, params, response_callback ) + { + if( 'generate' == command ) + { requestForShortenUrl + ( params.url + , params.code + , function ( data ) + { response_callback( data ) } + ) + } + } + + var requestForShortenUrl = function ( url, code, callback ) + { + var xhr = new XMLHttpRequest( ) + var form_data = new FormData( ) + + form_data.append( 'url', url ) + + if( code ) + { form_data.append( 'code', code ) } + + xhr.onload = function ( e ) + { + if( 201 == this.status ) + { callback + ({ 'status': 'OK' + , 'shortened_url' : this.getResponseHeader( 'Location' ) + }) + } + else + { callback + ({ 'status' : 'Error' + , 'error' : + { 'code' : this.status + , 'message' : this.responseText + } + }) + } + } + + xhr.open( 'POST', API_ENDPOINT, true ) + xhr.send( form_data ) + } + } + +chrome.extension.onRequest.addListener + ( function ( request, sender, sendResponse ) + { GitIO.invoke( request.command, request.params, sendResponse ) } + ) + +localStorage.getItem( 'notFirstRun', function ( arr ) + { + if( arr['notFirstRun'] ) return + + var shrtList = + { 'http://git.io/help' : 'https://github.com/blog/985-git-io-github-url-shortener' + , 'http://git.io/nn' : 'https://github.com/noformnocontent' + , 'http://git.io/chrome' : 'https://github.com/noformnocontent/git-io-chrome' + } + + localStorage.setItem( 'shrtList', shrtList ) + localStorage.setItem( 'notFirstRun', true ) + }) + + +var shrt_field = document.getElementById( 'shortened-url' ) + , url_field = document.getElementById( 'full-url' ) + , notifications = document.getElementById( 'notifications' ) + , message_field = document.getElementById( 'message' ) + , action_button = document.getElementById( 'action-button' ) + , show_all_recent_links = document.getElementById( 'show-all-recent-links' ) + , clear_list = document.getElementById( 'clear-list' ) + , recent_links = document.getElementById( 'recent-links' ) + , lis = recent_links.getElementsByTagName( 'li' ) + +var shrtLink = function ( ) + { getShortenedUrl( ) } + +action_button.addEventListener( 'click', shrtLink ) + +localStorage.getItem( function ( arr ) + { for( var k in arr ) + { createShrtListElement( k, arr[k]) } + }) + + +var setMessage = function ( message ) + { message_field.innerHTML = message } + +var copyResultToClipboard = function ( field ) + { + field.select( ) + document.execCommand( 'Copy' ) + notifications.classList.remove( 'error' ) + notifications.classList.add( 'done' ) + setMessage( 'Link is copied to the clipboard.' ) + } + +var bindBtnToCoopy = function ( ) + { + action_button.removeEventListener( 'click', shrtLink, false ) + action_button.addEventListener( 'click', function ( ) + { copyResultToClipboard( shrt_field ) }) + + action_button.innerHTML = 'cpy!' + action_button.classList.remove( 'error' ) + action_button.classList.add( 'done' ) + notifications.classList.remove( 'error' ) + notifications.classList.add( 'done' ) + setMessage( 'You can now copy the link by clicking “cpy!”' + + ' It will also stay in your shrt-list if you ever need it again.' + ) + } + +var createShrtListElement = function ( shrt, fullUrl, flashListsElement ) + { + if( !/^https?:\/\/git\.io\/.+/.test( shrt ) ) return + + var listElement = document.createElement( 'li' ) + , listInput = document.createElement( 'input' ) + , listVisit = document.createElement( 'a' ) + , listCopy = document.createElement( 'a' ) + + listInput.value = shrt + listInput.type = 'text' + listInput.readOnly = true + + listVisit.href = shrt + listVisit.target = '_new' + listVisit.title = 'Open link in new tab' + listVisit.appendChild( document.createTextNode( '' )) + + listCopy.href = '#copy' + listCopy.title = 'Copy link to clipboard' + listCopy.appendChild( document.createTextNode( '' )) + listCopy.addEventListener( 'click', function ( e ) + { + copyResultToClipboard + ( e.currentTarget.parentNode + .getElementsByTagName( 'input' )[0] + ) + e.preventDefault( ) + }) + + listElement.title = fullUrl + listElement.appendChild( listInput ) + listElement.appendChild( listVisit ) + listElement.appendChild( listCopy ) + + if( flashListsElement ) + { listElement.classList.add( 'current' ) } + + recent_links.insertBefore + ( listElement, recent_links.firstChild ) + + testShrtListLength( ) + } + +var getShortenedUrl = function ( ) + { + var request_data = + { 'command': 'generate' + , 'params': + { 'url': url_field + , 'code': shrt_field.value + } + } + + chrome.extension.sendRequest( request_data, function ( data ) + { + if( 'OK' == data.status ) + { + // TODO: notice if sent and recived shortened are different + shrt_field.value = data.shortened_url + bindBtnToCoopy( ) + localStorage.getItem( data.shortened_url, function ( arr ) + { + if( !arr[data.shortened_url] ) + { + var urlPair = { } + urlPair[data.shortened_url] = tab.url + localStorage.setItem( urlPair ) + } + else + { // bump to the top and '.current' the one in the list + } + }) + } + + else if( 'Error' == data.status ) + { + action_button.innerHTML = 'rrr!' + action_button.classList.remove( 'done' ) + action_button.classList.add( 'error' ) + notifications.classList.remove( 'done' ) + notifications.classList.add( 'error' ) + setMessage( data.error.code + ': ' + data.error.message ) + } + + else + { + action_button.innerHTML = '??!' + action_button.classList.remove( 'done' ) + action_button.classList.add( 'error' ) + notifications.classList.remove( 'done' ) + notifications.classList.add( 'error' ) + setMessage( data.status ) + } + }) + } + +var testShrtListLength = function ( ) + { + if( lis.length > 3 ) + { + show_all_recent_links.style.display = 'block' + show_all_recent_links.getElementsByTagName( 'li' )[0] + .innerHTML = '▾ show ' + ( lis.length-3 ) + ' more ▾' + + show_all_recent_links.addEventListener( 'click', function ( ) + { + for( var i = 3; i < lis.length; i++ ) + { lis[i].style.display = 'block' } + + show_all_recent_links.style.display = 'none' + clear_list.style.display = 'block' + + clear_list.addEventListener( 'click', function ( ) + { + while( lis[0] ) + { lis[0].parentNode.removeChild( lis[0]) } + + localStorage.clear( ) + localStorage.setItem( 'notFirstRun', true ) + clear_list.style.display = 'none' + }) + }) + } + } + +chrome.storage.onChanged.addListener( function ( changes, namespace ) + { + for( key in changes ) + { if( changes[key].newValue ) + { createShrtListElement( key, changes[key], true ) } + } + }) diff --git a/style.css b/style.css new file mode 100644 index 0000000..767b941 --- /dev/null +++ b/style.css @@ -0,0 +1,233 @@ +* { margin : 0 + ; padding : 0 + ; text-rendering : optimizeLegibility + } + +@font-face + { font-family : 'Octicons Regular' + ; src : url('octicons.woff') format('woff') + ; font-weight : normal + ; font-style : normal + } + +body + { font-family : sans-serif + ; font-size : 0 + ; background : #e7eef1 + ; padding : 15px + ; word-break : keep-all + ; white-space : nowrap + ; margin : 0 auto + ; width : 255px + } + +label + { font-size : 14px + ; background : linear-gradient(#839ba9, #415b6b) + ; border-radius : 3px 0 0 3px + ; border-top : solid 1px #313b3d + ; border-left : solid 1px #232b2c + ; border-bottom : solid 1px #232b2c + ; border-right : solid 1px #232b2c + ; box-shadow : 0 1px 3px #6a8290 inset + ; color : #e7eef1 + ; padding : 5px 7px 6px 7px + ; display : inline-block + ; letter-spacing : .075pt + ; line-height : 1rem + ; width : 37px + ; text-align : center + } + +label[for='full-url'] + { font-size : 12px } + +form + { display : inline } + +section + { margin-bottom : 15px } + +::-webkit-input-placeholder + { color : #b3bbbe } + +::input-placeholder + { color : #b3bbbe } + +#shortened-url +, #full-url + { background : #f7f9fa + ; font-size : 14px + ; color : #3b4448 + ; border-top : solid 1px #49565e + ; border-right : 0 + ; border-bottom : solid 1px #37434c + ; border-left : 0 + ; box-shadow : 0 1px 3px #6a8290 inset + ; vertical-align : top + ; padding : 3px 5px + ; height : 21px + ; width : 144px + } + +#full-url + { width : 192px + ; border-right : solid 1px #37434c + ; border-radius : 0 3px 3px 0 + } + +button + { width : 49px + ; height : 29px + ; font-size : 14px + ; line-height : 12px + ; background : linear-gradient(#425B6B, #24323B) + ; border-radius : 0 3px 3px 0 + ; border-top : solid 1px #313b3d + ; border-left : solid 1px #232b2c + ; border-bottom : solid 1px #232b2c + ; border-right : solid 1px #232b2c + ; box-shadow : 0 1px 0 #5f7886 inset + ; vertical-align : top + ; color : #fff + ; padding : 5px 7px + } + +button.done + { background : linear-gradient(#52a360, #477651) } + +button.error + { background : linear-gradient(#b24142, #803b3d) } + +ul + { width : 255px + ; font-size : 14px + ; list-style : none + ; margin-top : 15px + } + +ul li + { border : solid 1px #839ba9 + ; border-top : 0 + ; background : #e7eef1 + ; text-align : center + ; padding : 7px 5px + } + +ul li:first-child + { border-top : solid 1px #839ba9 + ; border-top-left-radius : 3px + ; border-top-right-radius : 3px + } + +ul li:last-child + { border-bottom-left-radius : 3px + ; border-bottom-right-radius : 3px + } + +#recent-links li + { display : none + ; padding : 0 + ; text-align : right + ; font-size : 0 + } + +#recent-links li:hover + { background : #f7f9fa } + +#recent-links li input + { float : left + ; font-size : 12px + ; width : 158px + ; padding : 2px + ; background : none + ; border : 0 + ; text-overflow : ellipsis + ; color : #839ba9 + ; margin : 5px 5px + } + +#recent-links li:hover input + { color : #3b4448 } + +#recent-links li a + { font-family : 'Octicons Regular' + ; visibility : hidden + ; text-decoration : none + ; text-align : center + ; padding : 3px + ; display : inline-block + ; color : #3b4448 + ; font-size : 16px + ; height : 24px + ; width : 24px + ; font-smoothing : antialiased + ; line-height : 1.5em + } + +#recent-links li:hover a + { visibility : visible } + +#recent-links li a:hover +, #recent-links li a:active +, #recent-links li a:focus + { background-image : linear-gradient(#5899cc, #3173b4) + ; color : #fff + } + +section + { box-shadow : 1px 1px 2px #6a8290 + ; border-radius : 3px + ; width : 255px + } + +#recent-links li:first-child +, #recent-links li:nth-child(2) +, #recent-links li:nth-child(3) + { display : block } + +#show-all-recent-links, #clear-list + { color : #839ba9 + ; display : none + ; cursor : pointer + ; font-size : 12px + ; line-height : 15px + ; margin-top : 0 + } + +#show-all-recent-links li + { color : #839ba9 + ; border-top-left-radius : 0 + ; border-top-right-radius : 0 + ; border-top : 0 + } + +#show-all-recent-links:hover li + { background : #f7f9fa + ; color : #3b4448 + } + +#clear-list + { margin-top : 15px } + +#clear-list:hover li + { background-color : #fee1e5 + ; color : #3b4448 + } + +#notifications li + { font-size : 11px + ; text-overflow : ellipsis + ; word-break : normal + ; white-space : normal + ; transition-property : background-color + ; transition-duration : 0.3s + ; background-color : #f7f9fa + } + +#notifications.done li +, #recent-links li.current + { background-color : #e5fae6 } + +#notifications.error li + { background-color : #fee1e5 }