@@ -37,6 +37,7 @@ define(function (require, exports, module) {
3737 FileUtils = brackets . getModule ( "file/FileUtils" ) ,
3838 Menus = brackets . getModule ( "command/Menus" ) ,
3939 PreferencesManager = brackets . getModule ( "preferences/PreferencesManager" ) ,
40+ LanguageManager = brackets . getModule ( "language/LanguageManager" ) ,
4041 Strings = brackets . getModule ( "strings" ) ,
4142 ViewUtils = brackets . getModule ( "utils/ViewUtils" ) ,
4243 TokenUtils = brackets . getModule ( "utils/TokenUtils" ) ;
@@ -48,7 +49,8 @@ define(function (require, exports, module) {
4849 $previewContainer , // Preview container
4950 $previewContent , // Preview content holder
5051 lastMousePos , // Last mouse position
51- animationRequest ; // Request for animation frame
52+ animationRequest , // Request for animation frame
53+ extensionlessImagePreview ; // Whether to try and preview extensionless URLs
5254
5355 // Constants
5456 var CMD_ENABLE_QUICK_VIEW = "view.enableQuickView" ,
@@ -60,6 +62,9 @@ define(function (require, exports, module) {
6062
6163 prefs = PreferencesManager . getExtensionPrefs ( "quickview" ) ;
6264 prefs . definePreference ( "enabled" , "boolean" , true ) ;
65+ // Whether or not to try and show image previews for URLs missing extensions
66+ // (e.g., https://avatars2.githubusercontent.com/u/476009?v=3&s=200)
67+ prefs . definePreference ( "extensionlessImagePreview" , "boolean" , true ) ;
6368
6469 /**
6570 * There are three states for this var:
@@ -451,67 +456,83 @@ define(function (require, exports, module) {
451456 }
452457 }
453458
454- if ( tokenString ) {
455- // Strip leading/trailing quotes, if present
456- tokenString = tokenString . replace ( / ( ^ [ ' " ] ) | ( [ ' " ] $ ) / g, "" ) ;
457-
458- if ( / ^ ( d a t a \: i m a g e ) | ( \. g i f | \. p n g | \. j p g | \. j p e g | \. w e b p | \. s v g ) $ / i. test ( tokenString ) ) {
459- var sPos , ePos ;
460- var docPath = editor . document . file . fullPath ;
461- var imgPath ;
462-
463- if ( PathUtils . isAbsoluteUrl ( tokenString ) ) {
464- imgPath = tokenString ;
465- } else {
466- imgPath = "file:///" + FileUtils . getDirectoryPath ( docPath ) + tokenString ;
467- }
468-
469- if ( urlMatch ) {
470- sPos = { line : pos . line , ch : urlMatch . index } ;
471- ePos = { line : pos . line , ch : urlMatch . index + urlMatch [ 0 ] . length } ;
472- } else {
473- sPos = { line : pos . line , ch : token . start } ;
474- ePos = { line : pos . line , ch : token . end } ;
475- }
476-
477- if ( imgPath ) {
478- var imgPreview = "<div class='image-preview'>" +
479- " <img src=\"" + imgPath + "\">" +
480- "</div>" ;
481- var coord = cm . charCoords ( sPos ) ;
482- var xpos = ( cm . charCoords ( ePos ) . left - coord . left ) / 2 + coord . left ;
483-
484- var showHandler = function ( ) {
485- // Hide the preview container until the image is loaded.
486- $previewContainer . hide ( ) ;
487-
488-
489- $previewContainer . find ( ".image-preview > img" ) . on ( "load" , function ( ) {
490- $previewContent
491- . append ( "<div class='img-size'>" +
492- this . naturalWidth + " × " + this . naturalHeight + " " + Strings . UNIT_PIXELS +
493- "</div>"
494- ) ;
495- $previewContainer . show ( ) ;
496- positionPreview ( editor , popoverState . xpos , popoverState . ytop , popoverState . ybot ) ;
497- } ) ;
498- } ;
499-
500- return {
501- start : sPos ,
502- end : ePos ,
503- content : imgPreview ,
504- onShow : showHandler ,
505- xpos : xpos ,
506- ytop : coord . top ,
507- ybot : coord . bottom ,
508- _imgPath : imgPath
509- } ;
510- }
511- }
459+ if ( ! tokenString ) {
460+ return null ;
512461 }
513-
514- return null ;
462+
463+ // Strip leading/trailing quotes, if present
464+ tokenString = tokenString . replace ( / ( ^ [ ' " ] ) | ( [ ' " ] $ ) / g, "" ) ;
465+
466+ var sPos , ePos ;
467+ var docPath = editor . document . file . fullPath ;
468+ var imgPath ;
469+
470+ // Determine whether or not this URL/path is likely to be an image.
471+ var parsed = PathUtils . parseUrl ( tokenString ) ;
472+ var hasProtocol = parsed . protocol !== "" ;
473+ var ext = parsed . filenameExtension . replace ( / ^ \. / , '' ) ;
474+ var language = LanguageManager . getLanguageForExtension ( ext ) ;
475+ var id = language && language . getId ( ) ;
476+ var isImage = id === "image" || id === "svg" ;
477+
478+ // Use this URL if this is an absolute URL and either points to a
479+ // filename with a known image extension, or lacks an extension (e.g.,
480+ // a web service that returns an image). Honour the extensionlessImagePreview
481+ // preference as well in the latter case.
482+ if ( hasProtocol && ( isImage || ( ! ext && extensionlessImagePreview ) ) ) {
483+ imgPath = tokenString ;
484+ }
485+ // Use this filename if this is a path with a known image extension.
486+ else if ( ! hasProtocol && isImage ) {
487+ imgPath = "file:///" + FileUtils . getDirectoryPath ( docPath ) + tokenString ;
488+ }
489+
490+ if ( ! imgPath ) {
491+ return null ;
492+ }
493+
494+ if ( urlMatch ) {
495+ sPos = { line : pos . line , ch : urlMatch . index } ;
496+ ePos = { line : pos . line , ch : urlMatch . index + urlMatch [ 0 ] . length } ;
497+ } else {
498+ sPos = { line : pos . line , ch : token . start } ;
499+ ePos = { line : pos . line , ch : token . end } ;
500+ }
501+
502+ var imgPreview = "<div class='image-preview'>" +
503+ " <img src=\"" + imgPath + "\">" +
504+ "</div>" ;
505+ var coord = cm . charCoords ( sPos ) ;
506+ var xpos = ( cm . charCoords ( ePos ) . left - coord . left ) / 2 + coord . left ;
507+
508+ var showHandler = function ( ) {
509+ // Hide the preview container until the image is loaded.
510+ $previewContainer . hide ( ) ;
511+
512+ $previewContainer . find ( ".image-preview > img" ) . on ( "load" , function ( ) {
513+ $previewContent
514+ . append ( "<div class='img-size'>" +
515+ this . naturalWidth + " × " + this . naturalHeight + " " + Strings . UNIT_PIXELS +
516+ "</div>"
517+ ) ;
518+ $previewContainer . show ( ) ;
519+ positionPreview ( editor , popoverState . xpos , popoverState . ytop , popoverState . ybot ) ;
520+ } ) . on ( "error" , function ( e ) {
521+ e . preventDefault ( ) ;
522+ hidePreview ( ) ;
523+ } ) ;
524+ } ;
525+
526+ return {
527+ start : sPos ,
528+ end : ePos ,
529+ content : imgPreview ,
530+ onShow : showHandler ,
531+ xpos : xpos ,
532+ ytop : coord . top ,
533+ ybot : coord . bottom ,
534+ _imgPath : imgPath
535+ } ;
515536 }
516537
517538
@@ -523,7 +544,6 @@ define(function (require, exports, module) {
523544 * Lacks only hoverTimer (supplied by handleMouseMove()) and marker (supplied by showPreview()).
524545 */
525546 function queryPreviewProviders ( editor , pos , token ) {
526-
527547 var line = editor . document . getLine ( pos . line ) ;
528548
529549 // FUTURE: Support plugin providers. For now we just hard-code...
@@ -720,6 +740,16 @@ define(function (require, exports, module) {
720740 CommandManager . get ( CMD_ENABLE_QUICK_VIEW ) . setChecked ( enabled ) ;
721741 }
722742
743+ function setExtensionlessImagePreview ( _extensionlessImagePreview , doNotSave ) {
744+ if ( extensionlessImagePreview !== _extensionlessImagePreview ) {
745+ extensionlessImagePreview = _extensionlessImagePreview ;
746+ if ( ! doNotSave ) {
747+ prefs . set ( "extensionlessImagePreview" , enabled ) ;
748+ prefs . save ( ) ;
749+ }
750+ }
751+ }
752+
723753 function setEnabled ( _enabled , doNotSave ) {
724754 if ( enabled !== _enabled ) {
725755 enabled = _enabled ;
@@ -787,10 +817,15 @@ define(function (require, exports, module) {
787817
788818 // Setup initial UI state
789819 setEnabled ( prefs . get ( "enabled" ) , true ) ;
820+ setExtensionlessImagePreview ( prefs . get ( "extensionlessImagePreview" ) , true ) ;
790821
791822 prefs . on ( "change" , "enabled" , function ( ) {
792823 setEnabled ( prefs . get ( "enabled" ) , true ) ;
793824 } ) ;
825+
826+ prefs . on ( "change" , "extensionlessImagePreview" , function ( ) {
827+ setExtensionlessImagePreview ( prefs . get ( "extensionlessImagePreview" ) ) ;
828+ } ) ;
794829
795830 // For unit testing
796831 exports . _queryPreviewProviders = queryPreviewProviders ;
0 commit comments