11import React from 'react' ;
22import ReactDOM from 'react-dom' ;
33import StoryControls from 'components/story/StoryControls' ;
4+ import StoryDescription from 'components/story/StoryDescription' ;
45
56var Clipboard = require ( 'clipboard' ) ;
67
@@ -13,12 +14,15 @@ var NoteView = require('./note_view');
1314var TaskForm = require ( './task_form' ) ;
1415var TaskView = require ( './task_view' ) ;
1516
17+ const LOCAL_STORY_REGEXP = / (? ! \s | \b ) ( # \d + ) (? ! \w ) / g;
18+
1619module . exports = FormView . extend ( {
1720
1821 template : require ( 'templates/story.ejs' ) ,
1922 alert : require ( 'templates/alert.ejs' ) ,
2023
2124 tagName : 'div' ,
25+ linkedStories : { } ,
2226
2327 initialize : function ( options ) {
2428 _ . extend ( this , _ . pick ( options , "isSearchResult" ) ) ;
@@ -326,7 +330,11 @@ module.exports = FormView.extend({
326330 this . model . clear ( ) ;
327331 } ,
328332
329- editDescription : function ( ) {
333+ editDescription : function ( ev ) {
334+ const $target = $ ( ev . target ) ;
335+ if ( $target . hasClass ( 'story-link' ) || $target . hasClass ( 'story-link-icon' ) )
336+ return ;
337+
330338 this . model . set ( { editingDescription : true } ) ;
331339 this . render ( ) ;
332340 } ,
@@ -358,7 +366,7 @@ module.exports = FormView.extend({
358366
359367 if ( this . id != undefined ) {
360368 var $wrapper = $ ( this . make ( 'div' , { class : 'col-xs-12 form-group input-group input-group-sm' , id : inputId } ) ) ;
361- var inputId = 'story-link -' + this . id ;
369+ var inputId = 'story-uri -' + this . id ;
362370
363371 $wrapper . append ( this . make ( 'input' , {
364372 id : inputId ,
@@ -378,6 +386,13 @@ module.exports = FormView.extend({
378386 $ ( btn ) . html ( '<img src="/clippy.svg" alt="Copy to clipboard" width="14px">' ) ;
379387 $btnWrapper . append ( btn ) ;
380388
389+ btn = this . make ( 'button' , {
390+ class : 'btn btn-default btn-clipboard-id btn-clipboard' ,
391+ 'data-clipboard-text' : '#' + this . id ,
392+ type : 'button'
393+ } , 'ID' ) ;
394+ $btnWrapper . append ( btn ) ;
395+
381396 // Story history button
382397 btn = this . make ( 'button' , { class : 'btn btn-default toggle-history' } )
383398 $ ( btn ) . html ( '<i class="mi md-18">history</i>' ) ;
@@ -490,7 +505,7 @@ module.exports = FormView.extend({
490505 this . $el . append (
491506 this . makeFormControl ( function ( div ) {
492507 $ ( div ) . append ( this . label ( "description" , I18n . t ( 'activerecord.attributes.story.description' ) ) ) ;
493- $ ( div ) . append ( '<br/>' ) ;
508+
494509 if ( this . model . isNew ( ) || this . model . get ( 'editingDescription' ) ) {
495510 var textarea = this . textArea ( "description" ) ;
496511 $ ( textarea ) . atwho ( {
@@ -499,21 +514,8 @@ module.exports = FormView.extend({
499514 } ) ;
500515 $ ( div ) . append ( textarea ) ;
501516 } else {
502- var description = this . make ( 'div' ) ;
503- $ ( description ) . addClass ( 'description' ) ;
504- $ ( description ) . html (
505- window . md . makeHtml ( this . model . escape ( 'description' ) )
506- ) ;
507- $ ( div ) . append ( description ) ;
508- if ( ! this . model . get ( 'description' ) || 0 === this . model . get ( 'description' ) . length ) {
509- $ ( description ) . after (
510- this . make ( 'input' , {
511- class : this . isReadonly ( ) ? '' : 'edit-description' ,
512- type : 'button' ,
513- value : I18n . t ( 'edit' )
514- } )
515- ) ;
516- }
517+ var $description = $ ( '<div class="description-wrapper"><div>' ) ;
518+ $ ( div ) . append ( $description ) ;
517519 }
518520 } )
519521 ) ;
@@ -564,6 +566,28 @@ module.exports = FormView.extend({
564566 /> ,
565567 this . $ ( '[data-story-controls]' ) . get ( 0 )
566568 ) ;
569+
570+ const descriptionContainer = this . $ ( '.description-wrapper' ) [ 0 ] ;
571+ if ( descriptionContainer ) {
572+ ReactDOM . render (
573+ < StoryDescription
574+ linkedStories = { this . linkedStories }
575+ isReadonly = { this . isReadonly ( ) }
576+ description = { this . parseDescription ( ) } /> ,
577+ descriptionContainer
578+ ) ;
579+ }
580+ } ,
581+
582+ parseDescription : function ( ) {
583+ const description = window . md . makeHtml ( this . model . escape ( 'description' ) ) || '' ;
584+ var id , story ;
585+ return description . replace ( LOCAL_STORY_REGEXP , story_id => {
586+ id = story_id . substring ( 1 ) ;
587+ story = this . model . collection . get ( id ) ;
588+ this . linkedStories [ id ] = story ;
589+ return ( story ) ? `<a data-story-id='${ id } '></a>` : story_id ;
590+ } ) ;
567591 } ,
568592
569593 setClassName : function ( ) {
@@ -697,22 +721,18 @@ module.exports = FormView.extend({
697721
698722 // FIXME Move to separate view
699723 hoverBox : function ( ) {
700- var view = this ;
701- this . $el . find ( '.popover-activate' ) . popover ( {
702- title : function ( ) {
703- return view . model . get ( "title" ) ;
704- } ,
705- content : function ( ) {
706- return require ( 'templates/story_hover.ejs' ) ( {
707- story : view . model ,
724+ if ( ! this . model . isNew ( ) ) {
725+ this . $el . find ( '.popover-activate' ) . popover ( {
726+ delay : 200 , // A small delay to stop the popovers triggering whenever the mouse is moving around
727+ html : true ,
728+ trigger : 'hover' ,
729+ title : ( ) => this . model . get ( "title" ) ,
730+ content : ( ) => require ( 'templates/story_hover.ejs' ) ( {
731+ story : this . model ,
708732 noteTemplate : require ( 'templates/note.ejs' )
709- } ) ;
710- } ,
711- // A small delay to stop the popovers triggering whenever the mouse is moving around
712- delay : 200 ,
713- html : true ,
714- trigger : 'hover'
715- } ) ;
733+ } )
734+ } ) ;
735+ }
716736 } ,
717737
718738 removeHoverbox : function ( ) {
0 commit comments