2011-03-23 10:51:00 +01:00
/ * *
* File : LeftAndMain . BatchActions . js
* /
( function ( $ ) {
2012-05-18 02:07:40 +02:00
$ . entwine ( 'ss.tree' , function ( $ ) {
2011-03-23 10:51:00 +01:00
/ * *
* Class : # Form _BatchActionsForm
*
* Batch actions which take a bunch of selected pages ,
* usually from the CMS tree implementation , and perform serverside
* callbacks on the whole set . We make the tree selectable when the jQuery . UI tab
* enclosing this form is opened .
*
* Events :
* register - Called before an action is added .
* unregister - Called before an action is removed .
* /
$ ( '#Form_BatchActionsForm' ) . entwine ( {
/ * *
* Variable : Actions
* ( Array ) Stores all actions that can be performed on the collected IDs as
* function closures . This might trigger filtering of the selected IDs ,
* a confirmation message , etc .
* /
Actions : [ ] ,
2012-06-12 12:48:08 +02:00
getTree : function ( ) {
return $ ( '.cms-tree' ) ;
} ,
fromTree : {
oncheck _node : function ( e , data ) {
this . serializeFromTree ( ) ;
2012-06-18 00:31:27 +02:00
} ,
onuncheck _node : function ( e , data ) {
this . serializeFromTree ( ) ;
2012-06-12 12:48:08 +02:00
}
} ,
2015-05-15 01:50:23 +02:00
/ * *
* Register default bulk confirmation dialogs
* /
registerDefault : function ( ) {
// Publish selected pages action
this . register ( 'admin/pages/batchactions/publish' , function ( ids ) {
var confirmed = confirm (
ss . i18n . inject (
ss . i18n . _t (
"CMSMAIN.BATCH_PUBLISH_PROMPT" ,
"You have {num} page(s) selected.\n\nDo you really want to publish?"
) ,
{ 'num' : ids . length }
)
) ;
return ( confirmed ) ? ids : false ;
} ) ;
// Unpublish selected pages action
this . register ( 'admin/pages/batchactions/unpublish' , function ( ids ) {
var confirmed = confirm (
ss . i18n . inject (
ss . i18n . _t (
"CMSMAIN.BATCH_UNPUBLISH_PROMPT" ,
"You have {num} page(s) selected.\n\nDo you really want to unpublish"
) ,
{ 'num' : ids . length }
)
) ;
return ( confirmed ) ? ids : false ;
} ) ;
// Delete selected pages action
// @deprecated since 4.0 Use archive instead
this . register ( 'admin/pages/batchactions/delete' , function ( ids ) {
var confirmed = confirm (
ss . i18n . inject (
ss . i18n . _t (
"CMSMAIN.BATCH_DELETE_PROMPT" ,
"You have {num} page(s) selected.\n\nDo you really want to delete?"
) ,
{ 'num' : ids . length }
)
) ;
return ( confirmed ) ? ids : false ;
} ) ;
// Delete selected pages action
this . register ( 'admin/pages/batchactions/archive' , function ( ids ) {
var confirmed = confirm (
ss . i18n . inject (
ss . i18n . _t (
"CMSMAIN.BATCH_ARCHIVE_PROMPT" ,
2015-08-03 06:17:31 +02:00
"You have {num} page(s) selected.\n\nAre you sure you want to archive these pages?\n\nThese pages and all of their children pages will be unpublished and sent to the archive."
2015-05-15 01:50:23 +02:00
) ,
{ 'num' : ids . length }
)
) ;
return ( confirmed ) ? ids : false ;
} ) ;
2015-08-03 05:56:58 +02:00
// Restore selected archived pages
this . register ( 'admin/pages/batchactions/restore' , function ( ids ) {
var confirmed = confirm (
ss . i18n . inject (
ss . i18n . _t (
"CMSMAIN.BATCH_RESTORE_PROMPT" ,
"You have {num} page(s) selected.\n\nDo you really want to restore to stage?\n\nChildren of archived pages will be restored to the root level, unless those pages are also being restored."
) ,
{ 'num' : ids . length }
)
) ;
return ( confirmed ) ? ids : false ;
} ) ;
2015-05-15 01:50:23 +02:00
// Delete selected pages from live action
this . register ( 'admin/pages/batchactions/deletefromlive' , function ( ids ) {
var confirmed = confirm (
ss . i18n . inject (
ss . i18n . _t (
"CMSMAIN.BATCH_DELETELIVE_PROMPT" ,
"You have {num} page(s) selected.\n\nDo you really want to delete these pages from live?"
) ,
{ 'num' : ids . length }
)
) ;
return ( confirmed ) ? ids : false ;
} ) ;
} ,
2012-06-12 12:48:08 +02:00
2011-03-23 10:51:00 +01:00
/ * *
* Constructor : onmatch
* /
2012-06-12 12:48:08 +02:00
onadd : function ( ) {
this . _updateStateFromViewMode ( ) ;
2015-05-15 01:50:23 +02:00
this . registerDefault ( ) ;
2012-06-12 12:48:08 +02:00
this . _super ( ) ;
} ,
2012-10-12 05:02:04 +02:00
'from .cms-content-batchactions :input[name=view-mode-batchactions]' : {
2012-06-12 12:48:08 +02:00
onclick : function ( e ) {
2012-10-12 05:02:04 +02:00
var checkbox = $ ( e . target ) , dropdown = this . find ( ':input[name=Action]' ) , tree = this . getTree ( ) ;
2012-06-12 12:48:08 +02:00
2012-10-12 05:02:04 +02:00
if ( checkbox . is ( ':checked' ) ) {
2011-03-23 10:51:00 +01:00
tree . addClass ( 'multiple' ) ;
2012-10-12 05:02:04 +02:00
tree . removeClass ( 'draggable' ) ;
2012-06-12 12:48:08 +02:00
this . serializeFromTree ( ) ;
2011-04-22 13:34:01 +02:00
} else {
2012-06-12 12:48:08 +02:00
tree . removeClass ( 'multiple' ) ;
2012-10-12 05:02:04 +02:00
tree . addClass ( 'draggable' ) ;
2011-03-23 10:51:00 +01:00
}
2012-03-08 01:03:49 +01:00
2012-06-12 12:48:08 +02:00
this . _updateStateFromViewMode ( ) ;
}
2012-05-14 01:43:36 +02:00
} ,
2012-06-12 12:48:08 +02:00
2012-05-11 02:53:40 +02:00
/ * *
* Updates the select box state according to the current view mode .
* /
_updateStateFromViewMode : function ( ) {
2012-10-12 05:02:04 +02:00
var viewMode = $ ( '.cms-content-batchactions :input[name=view-mode-batchactions]' ) ;
var batchactions = $ ( '.cms-content-batchactions' ) ;
2012-05-11 02:53:40 +02:00
var dropdown = this . find ( ':input[name=Action]' ) ;
// Batch actions only make sense when multiselect is enabled.
2012-10-12 05:02:04 +02:00
if ( viewMode . is ( ':checked' ) ) {
dropdown . trigger ( "liszt:updated" ) ;
batchactions . removeClass ( 'inactive' ) ;
}
else {
dropdown . trigger ( "liszt:updated" ) ;
// Used timeout to make sure when it shows up you won't see
// the native dropdown
setTimeout ( function ( ) { batchactions . addClass ( 'inactive' ) ; } , 100 ) ;
}
2015-08-21 06:22:08 +02:00
// Refresh selected / enabled nodes
$ ( '#Form_BatchActionsForm' ) . refreshSelected ( ) ;
2012-05-11 02:53:40 +02:00
} ,
2011-03-23 10:51:00 +01:00
/ * *
* Function : register
*
* Parameters :
*
* ( String ) type - ...
* ( Function ) callback - ...
* /
register : function ( type , callback ) {
this . trigger ( 'register' , { type : type , callback : callback } ) ;
var actions = this . getActions ( ) ;
actions [ type ] = callback ;
this . setActions ( actions ) ;
} ,
/ * *
* Function : unregister
*
* Remove an existing action .
*
* Parameters :
*
* { String } type
* /
unregister : function ( type ) {
this . trigger ( 'unregister' , { type : type } ) ;
var actions = this . getActions ( ) ;
if ( actions [ type ] ) delete actions [ type ] ;
this . setActions ( actions ) ;
} ,
/ * *
* Function : _isActive
*
* Determines if we should allow and track tree selections .
*
* Todo :
* Too much coupling with tabset
*
* Returns :
* ( boolean )
* /
_isActive : function ( ) {
2011-04-24 01:05:59 +02:00
return $ ( '.cms-content-batchactions' ) . is ( ':visible' ) ;
2011-03-23 10:51:00 +01:00
} ,
/ * *
* Function : refreshSelected
*
* Ajax callbacks determine which pages is selectable in a certain batch action .
*
* Parameters :
* { Object } rootNode
* /
refreshSelected : function ( rootNode ) {
2015-05-15 01:50:23 +02:00
var self = this ,
st = this . getTree ( ) ,
ids = this . getIDs ( ) ,
allIds = [ ] ,
2015-08-21 06:22:08 +02:00
viewMode = $ ( '.cms-content-batchactions :input[name=view-mode-batchactions]' ) ,
2015-11-03 20:35:25 +01:00
actionUrl = this . find ( ':input[name=Action]' ) . val ( ) ;
2011-03-23 10:51:00 +01:00
// Default to refreshing the entire tree
if ( rootNode == null ) rootNode = st ;
for ( var idx in ids ) {
$ ( $ ( st ) . getNodeByID ( idx ) ) . addClass ( 'selected' ) . attr ( 'selected' , 'selected' ) ;
}
2015-05-15 01:50:23 +02:00
// If no action is selected, enable all nodes
2015-11-03 20:35:25 +01:00
if ( ! actionUrl || actionUrl == - 1 || ! viewMode . is ( ":checked" ) ) {
2015-05-15 01:50:23 +02:00
$ ( rootNode ) . find ( 'li' ) . each ( function ( ) {
$ ( this ) . setEnabled ( true ) ;
} ) ;
return ;
}
// Disable the nodes while the ajax request is being processed
2011-03-23 10:51:00 +01:00
$ ( rootNode ) . find ( 'li' ) . each ( function ( ) {
allIds . push ( $ ( this ) . data ( 'id' ) ) ;
$ ( this ) . addClass ( 'treeloading' ) . setEnabled ( false ) ;
} ) ;
2015-05-15 01:50:23 +02:00
2011-03-23 10:51:00 +01:00
// Post to the server to ask which pages can have this batch action applied
2015-11-03 20:35:25 +01:00
// Retain existing query parameters in URL before appending path
var actionUrlParts = $ . path . parseUrl ( actionUrl ) ;
var applicablePagesUrl = actionUrlParts . hrefNoSearch + '/applicablepages/' ;
applicablePagesUrl = $ . path . addSearchParams ( applicablePagesUrl , actionUrlParts . search ) ;
applicablePagesUrl = $ . path . addSearchParams ( applicablePagesUrl , { csvIDs : allIds . join ( ',' ) } ) ;
jQuery . getJSON ( applicablePagesUrl , function ( applicableIDs ) {
2011-03-23 10:51:00 +01:00
// Set a CSS class on each tree node indicating which can be batch-actioned and which can't
jQuery ( rootNode ) . find ( 'li' ) . each ( function ( ) {
$ ( this ) . removeClass ( 'treeloading' ) ;
var id = $ ( this ) . data ( 'id' ) ;
if ( id == 0 || $ . inArray ( id , applicableIDs ) >= 0 ) {
$ ( this ) . setEnabled ( true ) ;
} else {
// De-select the node if it's non-applicable
$ ( this ) . removeClass ( 'selected' ) . setEnabled ( false ) ;
2015-05-15 01:50:23 +02:00
$ ( this ) . prop ( 'selected' , false ) ;
2011-03-23 10:51:00 +01:00
}
} ) ;
self . serializeFromTree ( ) ;
} ) ;
} ,
/ * *
* Function : serializeFromTree
*
* Returns :
* ( boolean )
* /
serializeFromTree : function ( ) {
var tree = this . getTree ( ) , ids = tree . getSelectedIDs ( ) ;
// write IDs to the hidden field
this . setIDs ( ids ) ;
return true ;
} ,
/ * *
* Function : setIDS
*
* Parameters :
* { Array } ids
* /
setIDs : function ( ids ) {
2012-03-08 01:27:47 +01:00
this . find ( ':input[name=csvIDs]' ) . val ( ids ? ids . join ( ',' ) : null ) ;
2011-03-23 10:51:00 +01:00
} ,
/ * *
* Function : getIDS
*
* Returns :
* { Array }
* /
getIDs : function ( ) {
2015-05-15 01:50:23 +02:00
// Map empty value to empty array
var value = this . find ( ':input[name=csvIDs]' ) . val ( ) ;
return value
? value . split ( ',' )
: [ ] ;
2011-03-23 10:51:00 +01:00
} ,
/ * *
* Function : onsubmit
*
* Parameters :
* ( Event ) e
* /
onsubmit : function ( e ) {
2015-05-15 01:50:23 +02:00
var self = this , ids = this . getIDs ( ) , tree = this . getTree ( ) , actions = this . getActions ( ) ;
2011-03-23 10:51:00 +01:00
// if no nodes are selected, return with an error
if ( ! ids || ! ids . length ) {
2015-05-15 01:50:23 +02:00
alert ( ss . i18n . _t ( 'CMSMAIN.SELECTONEPAGE' , 'Please select at least one page' ) ) ;
e . preventDefault ( ) ;
2011-03-23 10:51:00 +01:00
return false ;
}
// apply callback, which might modify the IDs
var type = this . find ( ':input[name=Action]' ) . val ( ) ;
2015-05-15 01:50:23 +02:00
if ( actions [ type ] ) {
ids = this . getActions ( ) [ type ] . apply ( this , [ ids ] ) ;
}
// Discontinue processing if there are no further items
if ( ! ids || ! ids . length ) {
e . preventDefault ( ) ;
return false ;
}
2011-03-23 10:51:00 +01:00
// write (possibly modified) IDs back into to the hidden field
this . setIDs ( ids ) ;
// Reset failure states
tree . find ( 'li' ) . removeClass ( 'failed' ) ;
var button = this . find ( ':submit:first' ) ;
button . addClass ( 'loading' ) ;
jQuery . ajax ( {
// don't use original form url
url : type ,
type : 'POST' ,
data : this . serializeArray ( ) ,
complete : function ( xmlhttp , status ) {
button . removeClass ( 'loading' ) ;
2012-03-08 01:27:47 +01:00
2015-07-15 04:58:48 +02:00
// Refresh the tree.
// Makes sure all nodes have the correct CSS classes applied.
tree . jstree ( 'refresh' , - 1 ) ;
2012-03-08 01:27:47 +01:00
self . setIDs ( [ ] ) ;
// Reset action
self . find ( ':input[name=Action]' ) . val ( '' ) . change ( ) ;
2011-03-23 10:51:00 +01:00
2012-05-14 15:13:49 +02:00
// status message (decode into UTF-8, HTTP headers don't allow multibyte)
2012-03-06 21:36:16 +01:00
var msg = xmlhttp . getResponseHeader ( 'X-Status' ) ;
2012-05-14 15:13:49 +02:00
if ( msg ) statusMessage ( decodeURIComponent ( msg ) , ( status == 'success' ) ? 'good' : 'bad' ) ;
2011-03-23 10:51:00 +01:00
} ,
success : function ( data , status ) {
2012-03-08 01:27:47 +01:00
var id , node ;
2011-03-23 10:51:00 +01:00
if ( data . modified ) {
2012-03-08 01:47:26 +01:00
var modifiedNodes = [ ] ;
2011-03-23 10:51:00 +01:00
for ( id in data . modified ) {
2012-03-08 01:27:47 +01:00
node = tree . getNodeByID ( id ) ;
2012-03-06 21:37:08 +01:00
tree . jstree ( 'set_text' , node , data . modified [ id ] [ 'TreeTitle' ] ) ;
2012-03-08 01:47:26 +01:00
modifiedNodes . push ( node ) ;
2011-03-23 10:51:00 +01:00
}
2012-03-08 01:47:26 +01:00
$ ( modifiedNodes ) . effect ( 'highlight' ) ;
2011-03-23 10:51:00 +01:00
}
if ( data . deleted ) {
for ( id in data . deleted ) {
2012-03-08 01:27:47 +01:00
node = tree . getNodeByID ( id ) ;
if ( node . length ) tree . jstree ( 'delete_node' , node ) ;
2011-03-23 10:51:00 +01:00
}
}
if ( data . error ) {
for ( id in data . error ) {
2012-03-08 01:27:47 +01:00
node = tree . getNodeByID ( id ) ;
2011-03-23 10:51:00 +01:00
$ ( node ) . addClass ( 'failed' ) ;
}
}
} ,
dataType : 'json'
} ) ;
2015-05-15 01:50:23 +02:00
// Never process this action; Only invoke via ajax
e . preventDefault ( ) ;
2011-03-23 10:51:00 +01:00
return false ;
}
} ) ;
/ * *
2012-05-11 05:31:12 +02:00
* Class : # Form _BatchActionsForm : select [ name = Action ]
2011-03-23 10:51:00 +01:00
* /
2012-05-11 05:31:12 +02:00
$ ( '#Form_BatchActionsForm select[name=Action]' ) . entwine ( {
onmatch : function ( ) {
this . trigger ( 'change' ) ;
this . _super ( ) ;
} ,
2012-05-14 01:43:36 +02:00
onunmatch : function ( ) {
this . _super ( ) ;
} ,
2012-05-11 05:31:12 +02:00
/ * *
* Function : onchange
*
* Parameters :
* ( Event ) e
* /
onchange : function ( e ) {
var form = $ ( e . target . form ) , btn = form . find ( ':submit' ) ;
if ( $ ( e . target ) . val ( ) == - 1 ) {
btn . attr ( 'disabled' , 'disabled' ) . button ( 'refresh' ) ;
} else {
btn . removeAttr ( 'disabled' ) . button ( 'refresh' ) ;
2015-05-15 01:50:23 +02:00
}
// Refresh selected / enabled nodes
$ ( '#Form_BatchActionsForm' ) . refreshSelected ( ) ;
2012-03-08 01:03:49 +01:00
2012-05-11 05:31:12 +02:00
// TODO Should work by triggering change() along, but doesn't - entwine event bubbling?
this . trigger ( "liszt:updated" ) ;
2012-03-08 01:03:49 +01:00
2012-05-11 05:31:12 +02:00
this . _super ( e ) ;
}
2011-03-23 10:51:00 +01:00
} ) ;
} ) ;
2012-05-11 02:53:40 +02:00
} ) ( jQuery ) ;