@ -11,382 +11,166 @@
var ModalHelper = ( function ( ) {
var ModalHelper = function ( timeline , options ) {
this . options = options ;
this . timeline = timeline ;
}
/ * * d i s p l a y t h e l o a d i n g m o d a l ( s p i n n e r i n a b o x )
* also fix z - index so it is always on top .
* /
ModalHelper . prototype . showLoadingModal = function ( ) {
jQuery ( '#ajax-indicator' ) . show ( ) . css ( 'zIndex' , 1020 ) ;
} ;
/** hide the loading modal */
ModalHelper . prototype . hideLoadingModal = function ( ) {
jQuery ( '#ajax-indicator' ) . hide ( ) ;
} ;
/ * * s u b m i t a f o r m i n t h e b a c k g r o u n d .
* @ param form : form element
* @ param url : url to submit to . can be undefined if so , url is taken from form .
* @ param callback : called with results
* /
//TODO fix this inconsistency w/ optional url.
ModalHelper . prototype . submitBackground = function ( form , url , callback ) {
var data = form . serialize ( ) ;
var ModalHelper = function ( ) {
this . _firstLoad = true ;
var modalHelper = this ;
var modalDiv , modalIframe ;
if ( typeof url === 'function' ) {
callback = url ;
url = undefined ;
}
function modalFunction ( e ) {
if ( ! e . ctrlKey && ! e . metaKey ) {
if ( jQuery ( e . target ) . attr ( "href" ) ) {
url = jQuery ( e . target ) . attr ( "href" ) ;
}
if ( typeof url === 'undefined' ) {
url = form . attr ( 'action' ) ;
}
if ( url ) {
e . preventDefault ( ) ;
jQuery . ajax ( {
type : 'POST' ,
url : url ,
data : data ,
error : function ( obj , error ) {
callback ( obj . status , obj . responseText ) ;
} ,
success : function ( response ) {
callback ( null , response ) ;
modalHelper . createModal ( url , function ( modalDiv ) { } ) ;
}
}
} ) ;
} ;
/ * * c r e a t e a p l a n n i n g m o d a l
* @ param type either new , edit or show .
* @ param projectId id of the project to create the modal for .
* @ param elementId element id to create the modal for . not needed for new type .
* @ param callback called when done
* /
ModalHelper . prototype . createPlanningModal = function ( type , projectId , elementId , callback ) {
var modalHelper = this ;
var timeline = modalHelper . timeline ;
var non _api _url = modalHelper . options . url _prefix +
modalHelper . options . project _prefix +
"/" +
projectId +
'/planning_elements/' ;
var api _url = modalHelper . options . url _prefix +
modalHelper . options . api _prefix +
modalHelper . options . project _prefix +
"/" +
projectId +
'/planning_elements/' ;
if ( typeof elementId === 'function' ) {
callback = elementId ;
elementId = undefined ;
}
// in the following lines we create the url to get the data from
// also we create the url we submit the data to for the edit action.
//TODO: escape projectId and elementId.
if ( type === 'new' ) {
jQuery ( document ) . ready ( function ( ) {
var body = jQuery ( document . body ) ;
// whatever globals there are, they need to be added to the
// prototype, so that all ModalHelper instances can share them.
if ( ModalHelper . _done !== true ) {
// one time initialization
modalDiv = jQuery ( '<div/>' ) . css ( 'hidden' , true ) . attr ( 'id' , 'modalDiv' ) ;
body . append ( modalDiv ) ;
non _api _url += 'new.js' ;
/** replace all data-modal links and all inside modal links */
body . on ( "click" , "[data-modal]" , modalFunction ) ;
modalDiv . on ( "click" , "a" , modalFunction ) ;
} else if ( type === 'edit' ) {
if ( typeof elementId === 'string' || typeof elementId === 'number' ) {
non _api _url += elementId + '/edit.js' ;
api _url += elementId + '.json' ;
// close when body is clicked
body . on ( "click" , ".ui-widget-overlay" , jQuery . proxy ( modalHelper . close , modalHelper ) ) ;
ModalHelper . _done = true ;
} else {
throw new Error ( 'need an element id for editing.' ) ;
modalDiv = jQuery ( '#modalDiv' ) ;
modalIframe = jQuery ( '#modalIframe' ) ;
}
} else if ( type === 'show' ) {
if ( typeof elementId === 'string' || typeof elementId === 'number' ) {
non _api _url += elementId + '.js' ;
} else {
modalHelper . modalDiv = modalDiv ;
modalHelper . modalIframe = modalIframe ;
} ) ;
throw new Error ( 'need an element id for showing.' ) ;
this . loadingModal = false ;
} ;
ModalHelper . prototype . tweakLink = function ( url ) {
if ( url ) {
if ( url . indexOf ( "?layout=false" ) == - 1 && url . indexOf ( "&layout=false" ) == - 1 ) {
return url + ( url . indexOf ( '?' ) != - 1 ? "&layout=false" : "?layout=false" ) ;
} else {
return url ;
}
} else {
throw new Error ( 'invalid action. allowed: new, show, edit' ) ;
}
} ;
//create the modal by using the html the url gives us.
modalHelper . createModal ( non _api _url , function ( ele ) {
var projects = timeline . projects ;
var project ;
var projectSelect ;
var fields = ele . find ( ':input' ) ;
ele . data ( 'changed' , false ) ;
ModalHelper . prototype . iframeLoadHandler = function ( ) {
try {
var modalDiv = this . modalDiv , modalIframe = this . modalIframe , modalHelper = this ;
var submitFunction = function ( e ) {
modalHelper . showLoadingModal ( ) ;
var content = modalIframe . contents ( ) ;
var body = content . find ( "body" ) ;
if ( type === 'new' ) {
if ( body . html ( ) !== "" ) {
this . hideLoadingModal ( ) ;
this . loadingModal = false ;
api _url = modalHelper . options . url _prefix +
modalHelper . options . api _prefix +
modalHelper . options . project _prefix +
"/" +
projectSelect . val ( ) +
'/planning_elements.json' ;
}
modalDiv . data ( 'changed' , false ) ;
modalHelper . submitBackground ( jQuery ( this ) , api _url , function ( err , res ) {
var element ;
modalHelper . hideLoadingModal ( ) ;
// display errors correctly.
if ( ! err ) {
currentURL = '' ;
timeline . reload ( ) ;
if ( elementId === undefined ) {
try {
// internet explorer has a text attribute instead of textContent.
element = res . getElementsByTagName ( 'id' ) [ 0 ] ;
elementId = element . textContent || element . text ;
} catch ( e ) {
console . log ( e ) ;
}
}
if ( elementId !== undefined ) {
modalHelper . createPlanningModal ( 'show' , projectId , elementId ) ;
}
} else if ( err !== '500' ) {
ele . find ( '.errorExplanation' ) . remove ( ) ;
var error = jQuery ( '<div>' ) . attr ( 'class' , 'errorExplanation' ) . attr ( 'id' , 'errorExplanation' ) ;
var json = jQuery . parseJSON ( res ) ;
var i , errorSpan , errorFormEle ;
var errorField ;
for ( errorField in json . errors ) {
if ( json . errors . hasOwnProperty ( errorField ) ) {
//for (i = 0; i < json.errors.length; i += 1) {
error . append (
jQuery ( '<ul/>' ) . append (
jQuery ( '<li/>' ) . text ( I18n . t ( 'js.timelines.' + errorField ) + ' ' + json . errors [ errorField ] ) )
) ;
try {
errorSpan = jQuery ( '<span/>' ) . attr ( 'class' , 'errorSpan' ) ;
errorFormEle = jQuery ( '#planning_element_' + errorField ) ;
errorFormEle . before ( errorSpan ) ;
errorSpan . append ( errorFormEle ) ;
} catch ( e ) {
// nop
}
}
}
ele . prepend ( error ) ;
ele . scrollTop ( 0 ) ;
body . on ( "click" , "a" , function ( e ) {
var url = jQuery ( e . target ) . attr ( "href" ) ;
if ( url ) {
jQuery ( e . target ) . attr ( "href" , modalHelper . tweakLink ( url ) ) ;
}
} ) ;
if ( e ) {
e . preventDefault ( ) ;
}
} ;
//if we want to create a new element, the project must be selectable.
if ( type === 'new' ) {
body . on ( "submit" , "form" , function ( e ) {
var url = jQuery ( e . target ) . attr ( "action" ) ;
ele . find ( 'tbody' ) . first ( ) . prepend (
jQuery ( '<tr><th>' + I18n . t ( 'js.timelines.create_planning_select_project' ) + '</th><td><select id="projectSelect"/></td></tr>' )
) ;
projectSelect = ele . find ( '#projectSelect' ) ;
for ( project in projects ) {
if ( projects . hasOwnProperty ( project ) ) {
if ( projects [ project ] . permissions . edit _planning _elements === true ) {
projectSelect . append ( jQuery ( '<option/>' ) . attr ( 'value' , projects [ project ] . identifier ) . text ( projects [ project ] . name ) ) ;
}
if ( url ) {
jQuery ( e . target ) . attr ( "action" , modalHelper . tweakLink ( url ) ) ;
}
}
projectSelect . change ( function ( ) {
var planningElementName = ele . find ( '#planning_element_name' ) . val ( ) ;
var planningElementDescription = ele . find ( '#planning_element_description' ) . val ( ) ;
var planningElementType = ele . find ( '#planning_element_planning_element_type_id' ) . val ( ) ;
var planningElementResponsible = ele . find ( '#planning_element_responsible_id' ) . val ( ) ;
var planningElementStartDate = ele . find ( '#planning_element_start_date' ) . val ( ) ;
var planningElementEndDate = ele . find ( '#planning_element_end_date' ) . val ( ) ;
//just overwrite the current planning modal.
modalHelper . createPlanningModal ( 'new' , projectSelect . val ( ) , function ( ele ) {
ele . find ( '#planning_element_name' ) . val ( planningElementName ) ;
ele . find ( '#planning_element_description' ) . val ( planningElementDescription ) ;
ele . find ( '#planning_element_planning_element_type_id' ) . val ( planningElementType ) ;
ele . find ( '#planning_element_responsible_id' ) . val ( planningElementResponsible ) ;
ele . find ( '#planning_element_start_date' ) . val ( planningElementStartDate ) ;
ele . find ( '#planning_element_end_date' ) . val ( planningElementEndDate ) ;
} ) ;
} ) ;
// set to given project id .
projectSelect . val ( projectId ) ;
}
//tweak body.
body . find ( "#footnotes_debug" ) . hide ( ) ;
body . css ( "min-width" , "0px" ) ;
//create cancel and save button
if ( type === 'new' || type === 'edit' ) {
var cancel = jQuery ( "<a>" ) . addClass ( "icon" ) . addClass ( "icon-cancel" ) . text ( I18n . t ( "js.timelines.cancel" ) ) . attr ( "href" , "#" ) . click ( function ( e ) {
e . preventDefault ( ) ;
if ( ele . data ( 'changed' ) !== true || confirm ( I18n . t ( 'js.timelines.really_close_dialog' ) ) ) {
if ( typeof elementId === "undefined" ) {
if ( ele . data ( 'changed' ) !== true || confirm ( I18n . t ( 'js.timelines.really_close_dialog' ) ) ) {
ele . data ( 'changed' , false ) ;
ele . dialog ( 'close' ) ;
}
} else {
modalHelper . createPlanningModal ( 'show' , projectId , elementId ) ;
}
}
body . find ( ":input" ) . change ( function ( ) {
modalDiv . data ( 'changed' , true ) ;
} ) ;
var save = jQuery ( "<a>" ) . addClass ( "icon" ) . addClass ( "icon-save" ) . text ( I18n . t ( "js.timelines.save" ) ) . attr ( "href" , "#" ) . click ( function ( e ) {
e . preventDefault ( ) ;
submitFunction . call ( ele . find ( 'form' ) ) ;
} ) ;
jQuery ( this ) . trigger ( "loaded" ) ;
ele . find ( 'form' ) . prepend (
jQuery ( "<div>" ) . append (
cancel
) . append (
save
) . addClass ( "contextual" )
) ;
//remove old submit/cancel elements
ele . find ( 'form' ) . find ( ':submit' ) . css ( "display" , "none" ) ;
ele . find ( 'form' ) . find ( '[name=cancelButton]' ) . remove ( ) ;
//make textareas bigger
if ( ele . height ( ) > 800 ) {
ele . find ( 'textarea' ) . attr ( "rows" , 10 ) ;
} else if ( ele . height ( ) > 600 ) {
ele . find ( 'textarea' ) . attr ( "rows" , 8 ) ;
}
}
modalDiv . parent ( ) . show ( ) ;
//overwrite the action for the edit button.
if ( type === 'show' ) {
modalIframe . attr ( "height" , modalDiv . height ( ) ) ;
} else {
this . showLoadingModal ( ) ;
}
} catch ( e ) {
this . loadingModal = false ;
this . hideLoadingModal ( ) ;
this . close ( ) ;
}
} ;
ele . find ( '.icon-edit' ) . click ( function ( e ) {
modalHelper . createPlanningModal ( 'edit' , projectId , elementId ) ;
e . preventDefault ( ) ;
} ) ;
/ * * d i s p l a y t h e l o a d i n g m o d a l ( s p i n n e r i n a b o x )
* also fix z - index so it is always on top .
* /
ModalHelper . prototype . showLoadingModal = function ( ) {
jQuery ( '#ajax-indicator' ) . show ( ) . css ( 'zIndex' , 1020 ) ;
} ;
ele . find ( '.icon-cancel' ) . click ( function ( e ) {
modalHelper . showLoadingModal ( ) ;
/** hide the loading modal */
ModalHelper . prototype . hideLoadingModal = function ( ) {
jQuery ( '#ajax-indicator' ) . hide ( ) ;
} ;
modalHelper . submitBackground ( jQuery ( ele . find ( '.icon-cancel' ) . parent ( ) [ 0 ] ) ,
function ( err , res ) {
modalHelper . hideLoadingModal ( ) ;
// display errors correctly.
if ( ! err ) {
ele . dialog ( 'close' ) ;
timeline . reload ( ) ;
}
}
) ;
ModalHelper . prototype . rewriteIframe = function ( ) {
this . destroyIframe ( ) ;
this . modalIframe = this . writeIframe ( this . modalDiv ) ;
} ;
e . preventDefault ( ) ;
} ) ;
ModalHelper . prototype . destroyIframe = function ( ) {
if ( this . modalIframe ) {
this . modalIframe . remove ( ) ;
}
} ;
ele . find ( '.icon-del' ) . click ( function ( e ) {
var tokenName , token , action , data = { } ;
var url = modalHelper . options . url _prefix +
modalHelper . options . project _prefix +
"/" +
projectId +
'/planning_elements/' ;
tokenName = jQuery ( 'meta[name=csrf-param]' ) . attr ( 'content' ) ;
token = jQuery ( 'meta[name=csrf-token]' ) . attr ( 'content' ) ;
if ( jQuery ( this ) . attr ( 'href' ) . indexOf ( "destroy" ) == - 1 ) {
modalHelper . showLoadingModal ( ) ;
action = 'delete' ;
data [ '_method' ] = 'delete' ;
data [ tokenName ] = token ;
jQuery . post ( url + elementId + '/move_to_trash' ,
data ,
function ( ) {
modalHelper . hideLoadingModal ( ) ;
ele . dialog ( 'close' ) ;
timeline . reload ( ) ;
} ) . error ( function ( ) {
modalHelper . hideLoadingModal ( ) ;
alert ( I18n . t ( 'js.timelines.error' ) ) ;
} ) ;
//move to bin
} else if ( confirm ( I18n . t ( 'js.timelines.really_delete_planning_element' ) ) ) {
modalHelper . showLoadingModal ( ) ;
action = 'delete' ;
data [ '_method' ] = 'delete' ;
data [ tokenName ] = token ;
data [ 'commit' ] = 'delete' ;
jQuery . post ( url + elementId ,
data ,
function ( ) {
modalHelper . hideLoadingModal ( ) ;
ele . dialog ( 'close' ) ;
timeline . reload ( ) ;
} ) . error ( function ( ) {
modalHelper . hideLoadingModal ( ) ;
alert ( I18n . t ( 'js.timelines.error' ) ) ;
} ) ;
//move to bin
}
ModalHelper . prototype . writeIframe = function ( div ) {
modalIframe = jQuery ( '<iframe/>' ) . attr ( "frameBorder" , "0px" ) . attr ( 'id' , 'modalIframe' ) . attr ( 'width' , '100%' ) . attr ( 'height' , '100%' ) . attr ( 'name' , 'modalIframe' ) ;
div . append ( modalIframe ) ;
e . preventDefault ( ) ;
} ) ;
}
modalIframe . bind ( "load" , jQuery . proxy ( this . iframeLoadHandler , this ) ) ;
fields . change ( function ( e ) {
ele . data ( 'changed' , true ) ;
} ) ;
return modalIframe ;
} ;
// calendar click must be stopped so it does not close the modal.
ele . find ( '.calendar-trigger' ) . click ( function ( ) {
jQuery ( '.calendar' ) . click ( function ( e ) {
e . stopPropagation ( ) ;
} ) . css ( 'zIndex' , 2000 ) ;
} ) ;
ModalHelper . prototype . close = function ( ) {
var modalDiv = this . modalDiv ;
if ( ! this . loadingModal ) {
if ( modalDiv && ( modalDiv . data ( 'changed' ) !== true || confirm ( I18n . t ( 'js.timelines.really_close_dialog' ) ) ) ) {
modalDiv . data ( 'changed' , false ) ;
modalDiv . dialog ( 'close' ) ;
// if a form is submitted, we stop it and submit it in the background.
ele . find ( 'form' ) . submit ( submitFunction ) ;
this . destroyIframe ( ) ;
if ( typeof callback === 'function' ) {
callback ( ele ) ;
jQuery ( this ) . trigger ( "closed" ) ;
}
} ) ;
}
} ;
ModalHelper . prototype . loading = function ( ) {
this . modalDiv . parent ( ) . hide ( ) ;
this . loadingModal = true ;
this . showLoadingModal ( ) ;
} ;
/ * * c r e a t e a m o d a l d i a l o g f r o m u r l h t m l d a t a
@ -394,140 +178,45 @@ var ModalHelper = (function() {
* @ param callback called when done . called with modal div .
* /
ModalHelper . prototype . createModal = function ( url , callback ) {
var modalHelper = this ;
var modalHelper = this , modalDiv = this . modalDiv , counter = 0 ;
url = this . tweakLink ( url ) ;
if ( modalHelper . loadingModal ) {
return ;
}
modalHelper . loadingModal = true ;
try {
modalHelper . showLoadingModal ( ) ;
// get html for url.
jQuery . ajax ( {
type : 'GET' ,
url : url ,
dataType : 'html' ,
error : function ( obj , error ) {
modalHelper . hideLoadingModal ( ) ;
modalHelper . loadingModal = false ;
} ,
success : function ( data ) {
try {
modalHelper . hideLoadingModal ( ) ;
currentURL = url ;
var ta = modalHelper . modalDiv ;
// write html to div
ta . html ( data ) ;
// show dialog.
ta . dialog ( {
modal : true ,
resizable : false ,
draggable : false ,
width : '900px' ,
height : jQuery ( window ) . height ( ) * 0.8 ,
position : {
my : 'center' ,
at : 'center'
}
} ) ;
// close when cancel is clicked.
ta . find ( '[name=cancelButton]' ) . click ( function ( e ) {
e . preventDefault ( ) ;
if ( ta . data ( 'changed' ) !== true || confirm ( I18n . t ( 'js.timelines.really_close_dialog' ) ) ) {
ta . data ( 'changed' , false ) ;
ta . dialog ( 'close' ) ;
}
} ) ;
// hide dialog header
//TODO: we need a default close button somewhere
jQuery ( '#planningElementDialog' ) . parent ( ) . prepend ( '<div id="ui-dialog-closer" />' ) ;
jQuery ( '.ui-dialog-titlebar' ) . hide ( ) ;
if ( typeof callback === 'function' ) {
callback ( ta ) ;
}
} catch ( e ) {
console . log ( e ) ;
} finally {
modalHelper . loadingModal = false ;
}
}
} ) ;
} catch ( e ) {
console . log ( e ) ;
modalHelper . loadingModal = false ;
}
} ;
ModalHelper . prototype . setup = function ( ) {
var body = jQuery ( 'body' ) ;
var timeline = this . timeline ;
var modalDiv ;
// whatever globals there are, they need to be added to the
// prototype, so that all ModalHelper instances can share them.
if ( ModalHelper . prototype . done !== true ) {
// one time initialization
modalDiv = jQuery ( '<div/>' ) . css ( 'hidden' , true ) . attr ( 'id' , 'planningElementDialog' ) ;
body . append ( modalDiv ) ;
// close when body is clicked
body . click ( function ( e ) {
if ( modalDiv . data ( 'changed' ) !== true || confirm ( I18n . t ( 'js.timelines.really_close_dialog' ) ) ) {
modalDiv . data ( 'changed' , false ) ;
modalDiv . dialog ( 'close' ) ;
} else {
e . stopPropagation ( ) ;
}
} ) ;
// do not close when element is clicked
modalDiv . click ( function ( e ) {
e . stopPropagation ( ) ;
} ) ;
ModalHelper . prototype . done = true ;
var calculatedHeight = jQuery ( window ) . height ( ) * 0.8 ;
this . modalIframe = modalHelper . writeIframe ( modalDiv ) ;
modalDiv . attr ( "height" , calculatedHeight ) ;
this . modalIframe . attr ( "height" , calculatedHeight ) ;
modalDiv . dialog ( {
modal : true ,
resizable : false ,
draggable : false ,
width : '900px' ,
height : calculatedHeight ,
position : {
my : 'center' ,
at : 'center'
} ,
closeOnEscape : false
} ) ;
} else {
if ( this . _firstLoad ) {
//add closer
modalDiv . parent ( ) . prepend ( '<div id="ui-dialog-closer" />' ) . click ( jQuery . proxy ( this . close , this ) ) ;
jQuery ( '.ui-dialog-titlebar' ) . hide ( ) ;
modalDiv = jQuery ( '#planningElementDialog' ) ;
this . _firstLoad = false ;
}
// every-time initialization
jQuery ( timeline ) . on ( 'dataLoaded' , function ( ) {
var projects = timeline . projects ;
var project ;
this . loading ( ) ;
for ( project in projects ) {
if ( projects . hasOwnProperty ( project ) ) {
if ( projects [ project ] . permissions . edit _planning _elements === true ) {
jQuery ( '#newPlanning' ) . show ( ) ;
break ;
}
}
}
} ) ;
var loadingModalDiv = jQuery ( '<div/>' ) ;
body . append ( loadingModalDiv ) ;
loadingModalDiv . css ( 'hidden' , true ) . attr ( 'id' , 'loadingModal' ) ;
this . loadingModal = false ;
this . modalDiv = modalDiv ;
}
this . modalIframe . attr ( "src" , url ) ;
} ;
return ModalHelper ;
} ) ( ) ;