7 [% INCLUDE 'doc-head-open.inc' %]
8 <title>Additional contents › Tools › Koha</title>
9 [% INCLUDE 'doc-head-close.inc' %]
11 [% SET editmode = "wysiwyg" %]
13 [% SET editmode = "text" %]
14 [% Asset.css("lib/codemirror/codemirror.css") | $raw %]
15 [% Asset.css("lib/codemirror/lint.min.css") | $raw %]
24 .syspref-link::before {
27 .customisation-link::before {
30 .customisation-link:first-child::before {
34 label[for^="content_"] {
40 <body id="tools_additional-contents" class="tools">
41 [% WRAPPER 'header.inc' %]
42 [% INCLUDE 'cat-search.inc' %]
45 [% WRAPPER 'sub-header.inc' %]
46 <nav id="breadcrumbs" aria-label="Breadcrumb" class="breadcrumb">
49 <a href="/cgi-bin/koha/mainpage.pl">Home</a>
52 <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a>
55 [% IF op == 'add_form' %]
57 [% IF category == 'news' %]
58 <a href="/cgi-bin/koha/tools/additional-contents.pl?category=news">News</a>
59 [% ELSIF category == 'pages' %]
60 <a href="/cgi-bin/koha/tools/additional-contents.pl?category=pages">Pages</a>
62 <a href="/cgi-bin/koha/tools/additional-contents.pl?category=html_customizations">HTML customizations</a>
66 <a href="#" aria-current="page">
67 [% IF additional_content.idnew %]
68 <span>Modify additional content</span>
70 <span>Add additional content</span>
72 ([% IF category == 'news' %]<span>News</span>[% ELSIF category == 'pages' %]<span>Pages</span>[% ELSE %]<span>HTML customizations</span>[% END %])
77 <a href="#" aria-current="page">
78 [% IF category == 'news' %]
80 [% ELSIF category == 'pages' %]
93 [% IF op == 'add_form' %]
94 <div class="main container-fluid">
96 <div class="col-md-10 col-md-offset-1 col-lg-8 col-lg-offset-2">
98 <div class="main container-fluid">
100 <div class="col-sm-10 col-sm-push-2">
105 [% FOR m IN messages %]
106 <div class="dialog [% m.type | html %]">
108 [% CASE 'error_on_update' %]
109 <span>An error occurred when updating this content. Perhaps it already exists</span>
110 [% CASE 'error_on_insert' %]
111 <span>An error occurred when adding this content. Check the logs</span>
112 [% CASE 'error_on_delete' %]
113 <span>An error occurred when deleting this content. Check the logs</span>
114 [% CASE 'success_on_update' %]
115 <span>Content updated successfully</span>
116 [% CASE 'success_on_insert' %]
117 <span>Content added successfully</span>
118 [% CASE 'success_on_delete' %]
119 <span>Content deleted successfully</span>
121 <span>[% m.code | html %]</span>
126 [% IF op == 'add_form' %]
127 [% PROCESS add_form %]
134 [% IF op != 'add_form' %]
135 </div> <!-- /.col-sm-10.col-sm-push-2 -->
137 <div class="col-sm-2 col-sm-pull-10">
140 <div id="news-filter">
141 <form action="/cgi-bin/koha/tools/additional-contents.pl" method="get">
143 <fieldset class="brief">
146 <label for="news_keyword">Keyword:</label>
147 <input type="text" name="news_keyword" id="news_keyword" />
150 <label for="news_display_location">Display location:</label>
151 <select name="news_display_location" id="news_display_location">
152 <option value="">All</option>
153 [% PROCESS locations_options category => category %]
157 <label for="news_library">Library: </label>
158 <select id="news_library" name="news_library">
159 <option value=""></option>
160 <option value="">All libraries</option>
161 [% PROCESS options_for_libraries libraries => Branches.all( selected => branchcode, unfiltered => 1, ) %]
166 <input type="checkbox" name="show_expired" id="show_expired" /> Show expired
174 [% INCLUDE 'tools-menu.inc' %]
176 </div> <!-- /.col-sm-2.col-sm-pull-10 -->
178 </div> <!-- /.row -->
179 </div> <!-- /.main.container-fluid -->
182 [% IF additional_content %]
183 <h1>Modify an additional content</h1>
185 <h1>New additional content ([% IF category == 'news' %]News[% ELSIF category == 'pages' %]Pages[% ELSE %]HTML customizations[% END %])</h1>
188 <div id="toolbar" class="btn-toolbar">
189 <div class="btn-group">
190 <button class="btn btn-primary" id="submit_form"><i class="fa fa-save"></i> Save</button>
191 <button class="btn btn-primary dropdown-toggle" data-toggle="dropdown">
192 <span class="caret"></span>
194 <ul class="dropdown-menu">
195 <li><a id="saveandcontinue" href="#">Save and continue editing</a></li>
198 [% IF category == 'news' %]
199 <a class="btn btn-default cancel" href="/cgi-bin/koha/tools/additional-contents.pl"><i class="fa fa-remove"></i> Cancel</a>
200 [% ELSIF category == 'pages' %]
201 <a class="btn btn-default cancel" href="/cgi-bin/koha/tools/additional-contents.pl?category=pages"><i class="fa fa-remove"></i> Cancel</a>
203 <a class="btn btn-default cancel" href="/cgi-bin/koha/tools/additional-contents.pl?category=html_customizations"><i class="fa fa-remove"></i> Cancel</a>
207 <form id="add_additional_content" method="post" action="/cgi-bin/koha/tools/additional-contents.pl" class="validate">
208 <input type="hidden" name="op" value="add_validate" />
209 <input type="hidden" name="category" value="[% category | html %]" />
210 <input type="hidden" name="code" value="[% additional_content.code | html %]" />
211 <input type="hidden" name="idnew" value="[% additional_content.idnew | html %]" />
212 <input type="hidden" id="redirect" name="redirect" value="" />
213 <input type="hidden" id="editmode" name="editmode" value="[% editmode | html %]" />
214 <fieldset class="rows">
217 <label for="location">Display location:</label>
218 <select id="location" name="location">
219 [% PROCESS locations_options location => additional_content.location %]
223 <label for="branchcode">Library: </label>
224 <select id="branchcode" name="branchcode">
225 [% IF additional_content.branchcode == '' %]
226 <option value="" selected="selected">All libraries</option>
228 <option value="">All libraries</option>
230 [% PROCESS options_for_libraries libraries => Branches.all( selected => additional_content.branchcode, unfiltered => 1, ) %]
233 [% UNLESS languages.size %]
235 [% IF category == 'news' %]
236 <label for="title" class="required">Title: </label>
237 <input id="title" size="100" maxlength="250" type="text" name="title_default" value="[% additional_content.title | html %]" required="required" class="required" /> <span class="required">Required</span>
239 <label for="title">Title: </label>
240 <input id="title" size="100" maxlength="250" type="text" name="title_default" value="[% additional_content.title | html %]" />
245 <label for="from">Publication date: </label>
246 <input id="from" type="text" name="published_on" size="15" value="[% additional_content.published_on | html %]" class="flatpickr" data-date_to="to" />
247 <div class="hint">[% INCLUDE 'date-format.inc' %]</div>
250 <label for="to">Expiration date: </label>
251 <input id="to" type="text" name="expirationdate" size="15" value="[% additional_content.expirationdate | html %]" class="flatpickr" />
253 [% INCLUDE 'date-format.inc' %]
254 [% IF category == 'news' %]
255 <br>News will still be accessible by direct URL if expired.
259 [% UNLESS category == 'pages' %]
261 <label for="number">Appear in position: </label>
262 [% IF ( additional_content.number ) %]
263 <input id="number" size="3" name="number" type="text" value="[% additional_content.number | html %]" />
265 <input id="number" size="3" name="number" type="text" />
272 [% IF languages.size %]
273 <div id="tabs" class="toptabs">
274 <ul class="nav nav-tabs" role="tablist">
275 [% FOR language IN languages %]
276 [% IF language.lang == 'default' %]
277 <li role="presentation"><a href="#lang_default" aria-controls="lang_default" role="tab" data-toggle="tab">Default</a></li>
279 <li role="presentation"><a href="#lang_[% language.lang | uri %]" aria-controls="lang_[% language.lang | uri %]" role="tab" data-toggle="tab">[% language.description | html %]</a></li>
283 <div class="tab-content">
284 [% FOR language IN languages %]
285 <div id="lang_[% language.lang | uri %]" class="lang clearfix tab-pane" data-lang="[% language.description | html %]">
289 <label for="title_[% language.lang | html %]">Title: </label>
290 <input id="title_[% language.lang| html %]" size="100" maxlength="250" type="text" name="title_[% language.lang | html %]" value="[% translated_contents.item(language.lang).title | html %]">
293 <label for="content_[% language.lang | html %]">Content: </label>
294 <textarea name="content_[% language.lang | html %]" id="content_[% language.lang | html %]" data-lang="[% language.lang | html%]" cols="75" rows="10">[% translated_contents.item(language.lang).content | html %]</textarea>
295 <input type="hidden" name="lang" value="[% language.lang | html %]" />
301 </div> <!-- /.tab-content -->
304 <div id="lang_default">
305 <div class="clearfix">
306 <textarea name="content" id="content_default" data-lang="[% language.lang | html %]" cols="75" rows="10">[% additional_content.content | html %]</textarea>
315 <div id="toolbar" class="btn-toolbar">
316 <div class="btn-group">
317 <a href="/cgi-bin/koha/tools/additional-contents.pl?op=add_form&category=[% category | uri %]&editmode=[% editmode | uri %]" class="btn btn-default" id="newentry"> <i class="fa fa-plus"></i> New entry</a><button class="btn btn-default dropdown-toggle" data-toggle="dropdown">
318 <span class="caret"></span>
320 <ul class="dropdown-menu pull-right">
323 <a href="/cgi-bin/koha/tools/additional-contents.pl?op=add_form&category=[% category | uri %]&editmode=text">New entry using text editor</a>
325 <a href="/cgi-bin/koha/tools/additional-contents.pl?op=add_form&category=[% category | uri %]&editmode=wysiwyg">New entry using WYSIWYG editor</a>
332 <h2>Additional contents ([% IF category == 'news' %]News[% ELSIF category == 'pages' %]Pages[% ELSE %]HTML customizations[% END %])</h2>
333 <span id="additional_contents_links">
335 <a class="customisation-link" href="/cgi-bin/koha/tools/additional-contents.pl?category=news">News</a>
336 <a class="customisation-link" href="/cgi-bin/koha/tools/additional-contents.pl?category=html_customizations">HTML customizations</a>
337 <a class="customisation-link" href="/cgi-bin/koha/tools/additional-contents.pl?category=pages">Pages</a>
338 [% IF ( CAN_user_parameters_manage_sysprefs ) %]
339 <a class="syspref-link" href='/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=OPACUserJS'>OPACUserJS</a>
340 <a class="syspref-link" href='/cgi-bin/koha/admin/preferences.pl?op=search&searchfield=OPACUserCSS'>OPACUserCSS</a>
344 [% IF additional_contents.count %]
345 <div class="page-section">
346 <form id="del_form" method="post" action="/cgi-bin/koha/tools/additional-contents.pl">
347 <table id="table_additional_contents">
350 <th class="NoSort"> </th>
354 <th>Publication date</th>
355 <th>Expiration date</th>
356 <th class="anti-the">Title</th>
358 [% IF category == 'pages' %]
360 <th class="anti-the">Page</th>
362 <th class="anti-the">News</th>
364 <th class="NoSort noExport">Actions</th>
368 [% FOREACH c IN additional_contents%]
369 [% IF ( c.is_expired ) %]<tr class="expired">[% ELSE %]<tr>[% END %]
371 <input type="checkbox" name="ids" value="[% c.idnew | html %]" />
374 [% IF c.category == 'news' || c.category == 'pages' %]
375 [% IF c.location == 'staff_and_opac' %]<span>All</span>
376 [% ELSIF c.location == 'staff_only' %]<span>Staff interface</span>
377 [% ELSIF c.location == 'opac_only' %]<span>OPAC</span>
378 [% ELSIF c.location == 'slip' %]<span>Slip</span>
379 [% ELSE %]<span>Unknown ('[% location | html %]')</span>
382 [% c.location | html %]
386 [% IF ( c.branchcode == "" ) -%]
388 [% ELSE %][% c.library.branchname | html %]
391 <td>[% c.number | html %]</td>
392 <td data-order="[% c.published_on | html %]">[% c.published_on | $KohaDates %]</td>
393 <td data-order="[% c.expirationdate | html %]">[% c.expirationdate | $KohaDates %] [% IF ( c.is_expired ) %](<span class="expired">expired</span>)[% END %]</td>
394 <td>[% c.title | html %]</td>
395 <td>[% IF ( c.author) %][% INCLUDE 'patron-title.inc' patron=c.author %][% END %]</td>
396 [% IF category == 'pages' %]
398 [% IF c.location == 'opac_only' OR c.location == 'staff_and_opac' %]
399 <strong>OPAC</strong>:
400 <a target="_blank" href="[% Koha.Preference('OPACBaseURL') | url %]/cgi-bin/koha/opac-page.pl?page_id=[% c.idnew | url %]" title="View on OPAC">Default</a>
402 <a target="_blank" href="[% Koha.Preference('OPACBaseURL') | url %]/cgi-bin/koha/opac-page.pl?code=[% c.code | url %]" title="View on OPAC">Current language</a>
404 [% IF c.location == 'staff_only' OR c.location == 'staff_and_opac' %]
405 [% IF c.location == 'staff_and_opac' %]<br/>[% END %]
406 <strong>Staff interface</strong>:
407 <a href="/cgi-bin/koha/tools/page.pl?page_id=[% c.idnew | url %]" title="View on staff interface">Default</a>
409 <a href="/cgi-bin/koha/tools/page.pl?code=[% c.code | url %]" title="View on staff interface">Current language</a>
414 <div class="btn-group">
415 <a class="preview_news btn btn-default btn-xs" data-number="[% loop.count | html %]"><i class="fa fa-eye" aria-hidden="true"></i> Preview content</a>
417 <div id="contentModal[% loop.count | html %]" class="modal" tabindex="-1" role="dialog" data-number="[% loop.count | html %]">
418 <div class="modal-dialog" role="document">
419 <div class="modal-content modal-lg">
420 <div class="modal-header">
421 <h5 class="modal-title">Preview of: "[% c.title | html %]"</h5>
423 <div class="modal-body">
424 [% c.content | $raw %]
426 <div class="modal-footer">
427 <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
433 <div class="btn-group dropup">
434 <a href="/cgi-bin/koha/tools/additional-contents.pl?op=add_form&id=[% c.idnew | uri %]&editmode=[% editmode | uri %]" class="btn btn-default btn-xs"> <i class="fa fa-pencil"></i> Edit</a><button class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown">
435 <span class="caret"></span>
437 <ul class="dropdown-menu pull-right">
440 <a href="/cgi-bin/koha/tools/additional-contents.pl?op=add_form&id=[% c.idnew | uri %]&editmode=text"><i class="fa fa-pencil"></i> Edit with text editor</a>
442 <a href="/cgi-bin/koha/tools/additional-contents.pl?op=add_form&id=[% c.idnew | uri %]&editmode=wysiwyg"><i class="fa fa-pencil"></i> Edit with WYSIWYG editor</a>
447 <div class="btn-group">
448 <a href="#" class="delete_news btn btn-default btn-xs" data-idnew="[% c.idnew | html %]"><i class="fa fa-trash"></i> Delete</a>
455 <input type="hidden" name="op" value="delete_confirmed" />
456 <input type="hidden" name="category" value="[% category | html %]" />
457 <fieldset class="action"><input type="submit" class="btn btn-primary" value="Delete selected" /></fieldset>
459 <form action="/cgi-bin/koha/tools/additional-contents.pl" method="post" id="delete_single">
460 <input type="hidden" id="del_op" name="op" value="delete_confirmed" />
461 <input type="hidden" id="del_category" name="category" value="[% category | html %]" />
462 <input type="hidden" id="del_ids" name="ids" />
464 </div> <!-- /.page-section -->
466 <div class="dialog message">There are no additional contents.</div>
470 [% BLOCK locations_options %]
471 [% IF category == 'news' || category == 'pages' %]
472 [% IF location == "staff_and_opac" %]
473 <option value="staff_and_opac" selected="selected">Staff interface and OPAC</option>
475 <option value="staff_and_opac">Staff interface and OPAC</option>
478 [% IF location == "staff_only" %]
479 <option value="staff_only" selected="selected">Staff interface</option>
481 <option value="staff_only">Staff interface</option>
484 [% IF location == "opac_only" %]
485 <option value="opac_only" selected="selected">OPAC</option>
487 <option value="opac_only">OPAC</option>
490 [% UNLESS category == 'pages' %]
491 [% IF location == "slip" %]
492 <option value="slip" selected="selected">Slip</option>
494 <option value="slip">Slip</option>
498 [% SET available_options = [ 'OpacNavRight', 'opacheader', 'OpacCustomSearch', 'OpacMainUserBlock', 'opaccredits', 'OpacLoginInstructions', 'OpacNav', 'OpacNavBottom', 'OpacSuggestionInstructions', 'ArticleRequestsDisclaimerText', 'OpacMoreSearches', 'OpacMySummaryNote', 'OpacLibraryInfo', 'CatalogConcernHelp', 'CatalogConcernTemplate' ] %]
499 [% FOREACH l IN available_options.sort %]
500 [% IF l == location %]
501 <option value="[% l | html %]" selected="selected">[% l | html %]</option>
503 <option value="[% l | html %]">[% l | html %]</option>
509 [% MACRO jsinclude BLOCK %]
510 [% INCLUDE 'calendar.inc' %]
511 [% Asset.js("js/tools-menu.js") | $raw %]
512 [% Asset.js("lib/hc-sticky.js") | $raw %]
514 $("#saveandcontinue").on("click",function(e){
516 $("#redirect").val("just_save");
517 $("#submit_form").click();
520 [% IF additional_contents.count %]
521 [% INCLUDE 'datatables.inc' %]
523 $('.preview_news').click( function() {
524 modalNumber = $(this).attr('data-number');
525 $('.modal[data-number="'+modalNumber+'"]').modal('show');
528 var form = document.getElementById('del_form');
529 var inputs = form.getElementsByTagName('input');
531 for (var i=0; i<inputs.length; i++) {
532 if (inputs[i].type == 'checkbox' && inputs[i].name == 'ids') {
533 checked = inputs[i].checked;
534 if (checked) return true;
539 function filterDataTable( table, column, term ){
541 table.column( column ).search( term ).draw();
543 table.search( term ).draw();
548 function clearFilter( term ){
550 $(".dt_button_clear_filter").addClass("disabled");
552 $(".dt_button_clear_filter").removeClass("disabled");
556 /* Custom table search configuration: If a table row
557 has an "expired" class, hide it UNLESS the
558 show_expired checkbox is checked */
559 $.fn.dataTable.ext.search.push(
560 function( settings, searchData, index, rowData, counter ) {
561 var row = $(settings.aoData[index].nTr);
562 if( row.hasClass("expired") && !$("#show_expired").prop("checked") ){
570 $(document).ready(function() {
572 var table = $("#table_additional_contents").DataTable($.extend(true, {}, dataTablesDefaults, {
573 "order": [[ 4, "desc" ]],
575 { "sortable": false, "searchable": false, 'targets': [ 'NoSort' ] },
576 { "type": "anti-the", "targets": [ "anti-the" ] }
578 "sPaginationType": "full_numbers"
581 $("#del_form").on("click", ".delete_news", function(e){
583 if( confirmDelete( _("Are you sure you want to delete this content? This cannot be undone.") ) ){
584 $("#del_ids").val( $(this).data("idnew") );
585 $("#delete_single").submit();
589 $("#del_form").on("submit",function(){
591 return confirmDelete( _("Are you sure you want to delete the selected content?") );
593 alert(_("Please select content to delete."));
598 $("#show_expired").on("change", function(){
599 /* redraw the DataTable according to the custom search function */
603 table.on( 'search.dt', function () {
604 var term = table.search();
605 $("#news_keyword").val( term );
608 $("#news_keyword").on("keyup", function(){
609 var term = $(this).val();
610 filterDataTable( table, null, term );
613 $("#news_display_location").on("change", function(){
614 var term = $(this).val();
615 filterDataTable( table, 1, term );
618 $("#news_library").on("change", function(){
619 // Table must be filtered by the <option>'s text, not its value
620 var opt = $(this).find("option:selected").text();
621 filterDataTable( table, 2, opt );
624 $(".dt_button_clear_filter").on("click", function(){
625 table.search('').columns().search('').draw();
626 $("#news-filter select").each(function(){
634 $(document).ready(function() {
635 [% IF category == 'news' %]
636 $("#add_additional_content").validate({
637 submitHandler: function(form){
638 if ( ! $("#title_default").val().length > 0 ) {
639 alert(_("Please specify a title for 'Default'"));
644 let content = $('#content_default').siblings(".CodeMirror")[0].CodeMirror.getValue();
646 let content = tinyMCE.get('content_default').getContent();
649 if ( ! content.length > 0 ) {
650 alert(__("Please specify a content for 'Default'"));
660 $("#submit_form").on("click",function(){
661 $("#add_additional_content").submit();
664 Sticky = $("#toolbar");
667 stickyClass: "floating"
673 [% UNLESS ( wysiwyg ) %]
674 [% Asset.js( "lib/codemirror/codemirror.min.js" ) | $raw %]
675 [% Asset.js( "lib/codemirror/xml.min.js" ) | $raw %]
676 [% Asset.js( "lib/codemirror/lint.min.js" ) | $raw %]
677 [% Asset.js( "lib/linters/htmlhint.min.js" ) | $raw %]
678 [% Asset.js( "lib/codemirror/html-lint.min.js" ) | $raw %]
680 let editors = new Object(); /* Keeps track of initialized CodeMirror instances */
681 $(document).ready(function(){
683 if( $("#tabs .tab-pane.active").length < 1 ){
684 /* Activate first tab and initialize its CodeMirror instance */
685 let firstTab = $("#tabs a:first");
686 firstTab.tab("show");
688 initCodeMirror( firstTab[0].hash );
692 $("#tabs a[data-toggle='tab']").on("shown.bs.tab", function (e) {
693 /* Try to initialize CodeMirror instance when tab opens */
694 initCodeMirror( e.target.hash );
698 function initCodeMirror( container ){
699 /* Initialize CodeMirror instance only if it doesn't exist */
700 if( !editors[ container ] ){
701 let textarea = $( container ).find("textarea[name^='content_']");
702 let this_lang = textarea.attr('data-lang');
703 let editor = CodeMirror.fromTextArea( document.getElementById('content_' + this_lang), {
708 gutters: ["CodeMirror-lint-markers"],
709 viewportMargin: Infinity,
711 editors[ container ] = editor;
717 [% Asset.js("lib/tiny_mce/tinymce.min.js") | $raw %]
718 [% INCLUDE 'str/tinymce_i18n.inc' %]
721 $(document).ready(function(){
722 if( $("#tabs").length > 0 && $("#tabs .tab-pane.active").length < 1 ){
723 /* Activate first tab and initialize its tinyMCE instance */
724 let firstTab = $("#tabs a:first");
725 firstTab.tab("show");
726 initTinyMce( firstTab[0].hash );
729 $("#tabs a[data-toggle='tab']").on("shown.bs.tab", function (e) {
730 /* Try to initialize tinyMCE instance when tab opens */
731 initTinyMce( e.target.hash );
735 function initTinyMce( container ){
736 let textarea = $( container ).find("textarea[name^='content_']");
737 /* TinyMCE seems to do its own check to prevent double-initialization
738 so We don't need to keep track of it */
739 let editor = tinyMCE.init({
741 block_unsupported_drop : false,
742 content_css : "[% interface | html %]/[% theme | html %]/css/tinymce.css",
743 custom_elements:"style,link,~link",
744 extended_valid_elements:"style,link[href|rel]",
745 force_br_newlines : false,
746 force_p_newlines : false,
747 forced_root_block : '',
748 menubar : "file edit view insert format tools table",
749 plugins : "autoresize table hr link image charmap lists code emoticons",
750 autoresize_bottom_margin: 60,
751 relative_urls : false,
752 selector: "#" + textarea[0].id,
755 "formatselect | bold italic | cut copy paste | alignleft aligncenter alignright | outdent indent | image link unlink anchor cleanup hr",
756 "table | bullist numlist | undo redo | removeformat | emoticons charmap | forecolor backcolor | code"
762 [% END # /UNLESS wysiwyg %]
765 [% INCLUDE 'intranet-bottom.inc' %]