use strict;
#use warnings; FIXME - Bug 2505
+
use C4::Context;
+
use Memoize;
+use DateTime;
+use DateTime::Format::MySQL;
+use autouse 'Data::Dumper' => qw(Dumper);
-use vars qw($VERSION @ISA @EXPORT $DEBUG);
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $DEBUG);
BEGIN {
$VERSION = 3.01;
$DEBUG
);
$DEBUG = 0;
+@EXPORT_OK = qw( GetDailyQuote );
}
# expensive functions
}
}
+=head2 GetDailyQuote($opts)
+
+Takes a hashref of options
+
+Currently supported options are:
+
+'id' An exact quote id
+'random' Select a random quote
+noop When no option is passed in, this sub will return the quote timestamped for the current day
+
+The function returns an anonymous hash following this format:
+
+ {
+ 'source' => 'source-of-quote',
+ 'timestamp' => 'timestamp-value',
+ 'text' => 'text-of-quote',
+ 'id' => 'quote-id'
+ };
+
+=cut
+
+# This is definitely a candidate for some sort of caching once we finally settle caching/persistence issues...
+# at least for default option
+
+sub GetDailyQuote {
+ my %opts = @_;
+ my $dbh = C4::Context->dbh;
+ my $query = '';
+ my $sth = undef;
+ my $quote = undef;
+ if ($opts{'id'}) {
+ $query = 'SELECT * FROM quotes WHERE id = ?';
+ $sth = $dbh->prepare($query);
+ $sth->execute($opts{'id'});
+ $quote = $sth->fetchrow_hashref();
+ }
+ elsif ($opts{'random'}) {
+ # Fall through... we also return a random quote as a catch-all if all else fails
+ }
+ else {
+ $query = 'SELECT * FROM quotes WHERE timestamp LIKE CONCAT(CURRENT_DATE,\'%\') ORDER BY timestamp LIMIT 0,1';
+ $sth = $dbh->prepare($query);
+ $sth->execute();
+ $quote = $sth->fetchrow_hashref();
+ }
+ unless ($quote) { # if there are not matches, choose a random quote
+ # get a list of all available quote ids
+ $sth = C4::Context->dbh->prepare('SELECT count(*) FROM quotes;');
+ $sth->execute;
+ my $range = ($sth->fetchrow_array)[0];
+ if ($range > 1) {
+ # chose a random id within that range if there is more than one quote
+ my $id = int(rand($range));
+ # grab it
+ $query = 'SELECT * FROM quotes WHERE id = ?;';
+ $sth = C4::Context->dbh->prepare($query);
+ $sth->execute($id);
+ }
+ else {
+ $query = 'SELECT * FROM quotes;';
+ $sth = C4::Context->dbh->prepare($query);
+ $sth->execute();
+ }
+ $quote = $sth->fetchrow_hashref();
+ # update the timestamp for that quote
+ $query = 'UPDATE quotes SET timestamp = ? WHERE id = ?';
+ $sth = C4::Context->dbh->prepare($query);
+ $sth->execute(DateTime::Format::MySQL->format_datetime(DateTime->now), $quote->{'id'});
+ }
+ return $quote;
+}
+
sub _normalize_match_point {
my $match_point = shift;
(my $normalized_match_point) = $match_point =~ /([\d-]*[X]*)/;
(13, 'moderate_comments', 'Benutzerkommentare moderieren'),
(13, 'edit_notices', 'Benachrichtigungen verwalten'),
(13, 'edit_notice_status_triggers', 'Mahntrigger für überfällige Medien verwalten'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Logs durchsuchen/einsehen'),
(13, 'inventory', 'Inventur durchführen'),
(13, 'stage_marc_import', 'MARC-Datensätze zwischenspeichern'),
(13, 'moderate_comments', 'Moderate patron comments'),
(13, 'edit_notices', 'Define notices'),
(13, 'edit_notice_status_triggers', 'Set notice/status triggers for overdue items'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Browse the system logs'),
(13, 'inventory', 'Perform inventory (stocktaking) of your catalog'),
(13, 'stage_marc_import', 'Stage MARC records into the reservoir'),
--- /dev/null
+/*!40000 ALTER TABLE `quotes` DISABLE KEYS */;
+INSERT INTO `quotes` VALUES
+(1,'George Washington','To be prepared for war is one of the most effectual means of preserving peace.','0000-00-00 00:00:00'),
+(2,'Thomas Jefferson','When angry, count ten, before you speak; if very angry, an hundred.','0000-00-00 00:00:00'),
+(3,'Abraham Lincoln','Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.','2012-04-12 20:30:59'),
+(4,'Abraham Lincoln','I have always found that mercy bears richer fruits than strict justice.','0000-00-00 00:00:00'),
+(5,'Andrew Johnson','I feel incompetent to perform duties...which have been so unexpectedly thrown upon me.','0000-00-00 00:00:00'),
+(6,'Rutherford B. Hayes','He serves his party best who serves his country best.','0000-00-00 00:00:00'),
+(7,'Theodore Roosevelt','No President has ever enjoyed himself as much as I?','0000-00-00 00:00:00'),
+(8,'Theodore Roosevelt','Speak softly and carry a big stick.','0000-00-00 00:00:00'),
+(9,'William H. Taft','I have come to the conclusion that the major part of the president is to increase the gate receipts of expositions and fairs and bring tourists to town.','0000-00-00 00:00:00'),
+(11,'Woodrow Wilson','You cannot become thorough Americans if you think of yourselves in groups. America does not consist of groups. A man who thinks of himself as belonging to a particular national group in America has not yet become an American.','0000-00-00 00:00:00'),
+(12,'Calvin Coolidge','If you don\'t say anything, you won\'t be called on to repeat it.','0000-00-00 00:00:00'),
+(13,'Calvin Coolidge','Four fifths of all our troubles in this life would disappear if we would only sit down and keep still.','0000-00-00 00:00:00'),
+(14,'Herbert Hoover','The slogan of progress is changing from the full dinner pail to the full garage.','0000-00-00 00:00:00'),
+(15,'Franklin D. Roosevelt','Let me assert my firm belief that the only thing we have to fear is fear itself.','0000-00-00 00:00:00'),
+(16,'Harry S. Truman','If you can\'t stand the heat, get out of the kitchen.','0000-00-00 00:00:00'),
+(17,'Harry S. Truman','The atom bomb was no great decision. It was merely another powerful weapon in the arsenal of righteousness.','0000-00-00 00:00:00'),
+(18,'Harry S. Truman','The buck stops here.','0000-00-00 00:00:00'),
+(19,'Dwight D. Eisenhower','History does not long entrust the care of freedom to the weak or the timid.','0000-00-00 00:00:00'),
+(20,'John F. Kennedy','My fellow Americans, ask not what your country can do for you; ask what you can do for your country.','0000-00-00 00:00:00'),
+(22,'John F. Kennedy','I do not think it altogether inappropriate to introduce myself to this audience. I am the man who accompanied Jacqueline Kennedy to Paris, and I have enjoyed it.','0000-00-00 00:00:00'),
+(23,'Lyndon B. Johnson','The Great Society is a place where every child can find knowledge to enrich his mind and to enlarge his talents. It is a place where the city of man serves not only the needs of the body and the demands of commerce but the desire for beauty and the hunger for community. It is a place where men are more concerned with the quality of their goals than the quantity of their goods.','0000-00-00 00:00:00'),
+(24,'Richard Nixon','People have got to know whether or not their president is a crook. Well, I\'m not a crook.','0000-00-00 00:00:00'),
+(25,'Richard Nixon','When the President does it, that means that it is not illegal.','0000-00-00 00:00:00'),
+(26,'Gerald R. Ford','Our Long national nightmare is over.','2012-04-18 19:42:14'),
+(27,'Gerald R. Ford','Our constitution works. Our great republic is a government of laws, not of men.','0000-00-00 00:00:00'),
+(28,'Jimmy Carter','A strong nation, like a strong person, can afford to be gentle, firm, thoughtful, and restrained. It can afford to extend a helping hand to others. It\'s a weak nation, like a weak person, that must behave with bluster and boasting and rashness and other signs of insecurity.','0000-00-00 00:00:00'),
+(30,'Ronald Reagan','It is not my intention to do away with government. It is rather to make it work -work with us, not over us; stand by our side, not ride on our back. Government can and must provide opportunity, not smother it; foster productivity, not stifle it. This Administration\'s objective will be a healthy, vigorous, growing economy.','0000-00-00 00:00:00'),
+(31,'Ronald Reagan','Each generation goes further than the generation preceding it because it stands on the shoulders of that generation. You will have opportunities beyond anything we\'ve ever known.','0000-00-00 00:00:00'),
+(32,'George H. W. Bush ','We have ...drawn a line in the sand.','0000-00-00 00:00:00'),
+(33,'George W. Bush','If America shows weakness and uncertainty, the world will drift toward tragedy. That will not happen on my watch.','0000-00-00 00:00:00'),
+(34,'George W. Bush','Every nation in every region now has a decision to make. Either you are with us, or you are with the terrorists.','0000-00-00 00:00:00');
+/*!40000 ALTER TABLE `quotes` ENABLE KEYS */;
--- /dev/null
+Sample Quotes
(13, 'moderate_comments', 'Modérer les commentaires des adhérents'),
(13, 'edit_notices', 'Définir les notifications'),
(13, 'edit_notice_status_triggers', 'Définir les déclencheurs de notification de retard'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Parcourir les journaux de l''activité du système'),
(13, 'inventory', 'Réaliser les tâches de récolement'),
(13, 'stage_marc_import', 'Importer des notices MARC dans le réservoir'),
(13, 'moderate_comments', 'Modera i commenti degli utenti'),
(13, 'edit_notices', 'Definisci le notifiche'),
(13, 'edit_notice_status_triggers', 'Imposta il messaggio o lo stato delle notifiche per le copie in ritardo'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Scorri i log di sistema'),
(13, 'inventory', 'Lavora sugli inventari (stocktaking) del tuo catalogo'),
(13, 'stage_marc_import', 'Opera sui Record MARC presenti nella zona di lavoro'),
CONSTRAINT ratings_ibfk_2 FOREIGN KEY (biblionumber) REFERENCES biblio (biblionumber) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+--
+-- Table structure for table `quotes`
+--
+
+DROP TABLE IF EXISTS quotes;
+CREATE TABLE `quotes` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `source` varchar(45) DEFAULT NULL,
+ `text` mediumtext NOT NULL,
+ `timestamp` datetime NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8
+
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
(13, 'moderate_comments', 'Behandle kommentarer fra lånere'),
(13, 'edit_notices', 'Definere meldinger'),
(13, 'edit_notice_status_triggers', 'Definere utløsere for meldinger og statusenderinger for for sent leverte dokumenter'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Se Koha sine logger'),
(13, 'inventory', 'Foreta varetelling'),
(13, 'stage_marc_import', 'Importere MARC-poster til brønnen'),
(13, 'moderate_comments', 'Moderate patron comments'),
(13, 'edit_notices', 'Define notices'),
(13, 'edit_notice_status_triggers', 'Set notice/status triggers for overdue items'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Przeglądanie logów systemowych'),
(13, 'inventory', 'Perform inventory (stocktaking) of your catalog'),
(13, 'stage_marc_import', 'Stage MARC records into the reservoir'),
(13, 'moderate_comments', 'Регулировка комментариев от посетителей'),
(13, 'edit_notices', 'Определение сообщений'),
(13, 'edit_notice_status_triggers', 'Установка триггеров сообщений/статусов для просроченных экземпляров'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Просмотр протоколов системы'),
(13, 'inventory', 'Проведение инвентаризации(анализа) Вашего каталога'),
(13, 'stage_marc_import', 'Заготовка МАРК-записей в хранилище'),
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OpacPublic',1,'Turn on/off public OPAC',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserjs','','Define custom javascript for inclusion in OPAC','70|10','Textarea');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('opacuserlogin',1,'Enable or disable display of user login features',NULL,'YesNo');
+INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('QuoteOfTheDay',0,'Enable or disable display of Quote of the Day on the OPAC home page',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('patronimages',0,'Enable patron images for the Staff Client',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('OPACpatronimages',0,'Enable patron images in the OPAC',NULL,'YesNo');
INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES('printcirculationslips',1,'If ON, enable printing circulation receipts','','YesNo');
(13, 'moderate_comments', 'Регулювання коментарів від відвідувачів'),
(13, 'edit_notices', 'Визначення повідомлень'),
(13, 'edit_notice_status_triggers', 'Встановлення тригерів повідомлень/статусів для прострочених примірників'),
+ (13, 'edit_quotes', 'Edit quotes for quote-of-the-day feature'),
(13, 'view_system_logs', 'Перегляд протоколів системи'),
(13, 'inventory', 'Проведення інвентаризації(аналізу) Вашого каталогу'),
(13, 'stage_marc_import', 'Заготівля МАРК-записів у сховище'),
SetVersion($DBversion);
}
+$DBversion = "3.09.00.XXX";
+if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
+ unless (TableExists('quotes')) {
+ $dbh->do( qq{
+ CREATE TABLE `quotes` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `source` varchar(45) DEFAULT NULL,
+ `text` mediumtext NOT NULL,
+ `timestamp` datetime NOT NULL,
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8
+ });
+ }
+ $dbh->do( qq{
+ INSERT IGNORE INTO permissions VALUES (13, "edit_quotes","Edit quotes for quote-of-the-day feature");
+ });
+ $dbh->do( qq{
+ INSERT IGNORE INTO `systempreferences` (variable,value,explanation,options,type) VALUES('QuoteOfTheDay',0,'Enable or disable display of Quote of the Day on the OPAC home page',NULL,'YesNo');
+ });
+ print "Upgrade to $DBversion done (Adding Quote of the Day Option.)\n";
+ SetVersion($DBversion);
+}
+
=head1 FUNCTIONS
=head2 TableExists($table)
.paging_full_numbers a.paginate_button.first {
background-image : url('../../img/first.png');
background-repeat: no-repeat;
- background-position : 2px center;
+ background-position : 1% center;
padding-left : 2em;
}
.paging_full_numbers a.paginate_button.previous {
background-image : url('../../img/prev.png');
background-repeat: no-repeat;
- background-position : 2px center;
+ background-position : 1% center;
padding-left : 2em;
}
.paging_full_numbers a.paginate_button.next {
background-image : url('../../img/next.png');
background-repeat: no-repeat;
- background-position : right center;
+ background-position : 96% center;
padding-right : 2em;
}
.paging_full_numbers a.paginate_button.last {
background-image : url('../../img/last.png');
background-repeat: no-repeat;
- background-position : right center;
+ background-position : 96% center;
border-right : 1px solid #686868;
padding-right : 2em;
}
cursor: pointer;
}
+.dataTables_processing {
+ background-color: white;
+ border: 1px solid #DDDDDD;
+ color: #999999;
+ font-size: 14px;
+ height: 30px;
+ left: 50%;
+ margin-left: -125px;
+ margin-top: -15px;
+ padding: 14px 0 2px;
+ position: fixed;
+ text-align: center;
+ top: 50%;
+ width: 250px;
+}
/*
table.display {
text-decoration: none;
}
+.yui-button {
+ border-radius: 5px;
+}
+
+.yui-button .first-child {
+ border-radius: 5px;
+}
+
.yui-button,.yui-button a:link,.yui-button a:visited {
color : #000;
}
--- /dev/null
+<script type="text/javascript">
+ //<![CDATA[
+ // prepare DOM for YUI Toolbar
+ $(document).ready(function() {
+ $("#add_quote").empty();
+ $("#delete_quote").empty();
+ $("#import_quotes").empty();
+ yuiToolbar();
+ });
+
+ // YUI Toolbar Functions
+ function yuiToolbar() {
+
+ new YAHOO.widget.Button({
+ type: "button",
+ label: _("Add quote"),
+ name: "add",
+ container: "add_quote",
+ onclick: {fn: fnClickAddRow}
+ });
+
+ new YAHOO.widget.Button({
+ type: "button",
+ label: _("Delete quote(s)"),
+ name: "delete",
+ container: "delete_quote",
+ onclick: {fn: fnClickDeleteRow}
+ });
+
+ new YAHOO.widget.Button({
+ type: "button",
+ label: _("Import quotes"),
+ name: "import",
+ container: "import_quotes",
+ onclick: {fn: function (){parent.location="quotes-upload.pl";}}
+ });
+ }
+
+//]]>
+</script>
+<div id="toolbar">
+ <ul class="toolbar">
+ <li id="add_quote"><a id="add" href="#">Add quote</a></li>
+ <li id="delete_quote"><a id="delete" href="#">Delete quote(s)</a></li>
+ <li id="import_quotes"><a id="import" href="#">Import quotes</a></li>
+ <span class="hint" style="">Click Source or Text field to edit contents. Press <Enter> to save changes.</span>
+ </ul>
+</div>
[% IF ( CAN_user_tools_schedule_tasks ) %]
<li><a href="/cgi-bin/koha/tools/scheduler.pl">Task scheduler</a></li>
[% END %]
+ [% IF ( CAN_user_tools_edit_quotes ) %]
+ <li><a href="/cgi-bin/koha/tools/quotes.pl">Quote editor</a></li>
+ [% END %]
</ul></div></div>
--- /dev/null
+$.fn.dataTableExt.oApi.fnReloadAjax = function ( oSettings, sNewSource, fnCallback, bStandingRedraw )
+{
+ if ( typeof sNewSource != 'undefined' && sNewSource != null )
+ {
+ oSettings.sAjaxSource = sNewSource;
+ }
+ this.oApi._fnProcessingDisplay( oSettings, true );
+ var that = this;
+ var iStart = oSettings._iDisplayStart;
+ var aData = [];
+
+ this.oApi._fnServerParams( oSettings, aData );
+
+ oSettings.fnServerData( oSettings.sAjaxSource, aData, function(json) {
+ /* Clear the old information from the table */
+ that.oApi._fnClearTable( oSettings );
+
+ /* Got the data - add it to the table */
+ var aData = (oSettings.sAjaxDataProp !== "") ?
+ that.oApi._fnGetObjectDataFn( oSettings.sAjaxDataProp )( json ) : json;
+
+ for ( var i=0 ; i<aData.length ; i++ )
+ {
+ that.oApi._fnAddData( oSettings, aData[i] );
+ }
+
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+ that.fnDraw();
+
+ if ( typeof bStandingRedraw != 'undefined' && bStandingRedraw === true )
+ {
+ oSettings._iDisplayStart = iStart;
+ that.fnDraw( false );
+ }
+
+ that.oApi._fnProcessingDisplay( oSettings, false );
+
+ /* Callback user function - for event handlers etc */
+ if ( typeof fnCallback == 'function' && fnCallback != null )
+ {
+ fnCallback( oSettings );
+ }
+ }, oSettings );
+}
+
+/* Example call to load a new file */
+//oTable.fnReloadAjax( 'media/examples_support/json_source2.txt' );
+
+/* Example call to reload from original file */
+//oTable.fnReloadAjax();
yes: Enable
no: Disable
- browsing and paging search results from the OPAC detail page.
-
+ -
+ - pref: QuoteOfTheDay
+ default: 0
+ choices:
+ yes: Enable
+ no: Disable
+ - Quote of the Day display on OPAC home page
Policy:
-
- pref: singleBranchMode
--- /dev/null
+ [% INCLUDE 'doc-head-open.inc' %]
+ <title>Koha › Tools › Quote editor</title>
+ [% INCLUDE 'doc-head-close.inc' %]
+ <link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
+ <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
+ <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/dataTables.fnReloadAjax.js"></script>
+ [% INCLUDE 'datatables-strings.inc' %]
+ </script>
+ <script type="text/javascript" src="/intranet-tmpl/prog/en/js/datatables.js"></script>
+ <script type="text/javascript" src="/intranet-tmpl/prog/en/js/jquery.jeditable.mini.js"></script>
+ <script type="text/javascript">
+ //<![CDATA[
+ var oTable; /* oTable needs to be global */
+ var sEmptyTable = _('No quotes available. Please use the \"Add Quote\" button to add a quote.'); /* override the default message in datatables-strings.inc */
+ $(document).ready(function() {
+ /* NOTE: This is an ajax-source datatable and *not* a server-side sourced datatable. */
+ /* See the datatable docs if you don't understand this difference. */
+ oTable = $("#quotes_editor").dataTable({
+ "bAutoWidth" : false,
+ "bProcessing" : true,
+ "bPaginate" : true,
+ "sPaginationType" : "full_numbers",
+ "sAjaxSource" : "/cgi-bin/koha/tools/quotes/quotes_ajax.pl",
+ "aoColumns" : [
+ { "sWidth": "3%" },
+ { "sWidth": "11%" },
+ { "sWidth": "75%" },
+ { "sWidth": "11%" },
+ ],
+ "oLanguage" : {
+ "sEmptyTable": sEmptyTable,
+ },
+ "fnPreDrawCallback": function(oSettings) {
+ return true;
+ },
+ "fnRowCallback": function( nRow, aData, iDisplayIndex ) {
+ /* do foo on the current row and its child nodes */
+ var noEditFields = [];
+ var quoteID = $('td', nRow)[0].innerHTML;
+ $(nRow).attr("id", quoteID); /* set row ids to quote id */
+ $('td:eq(0)', nRow).click(function() {$(this.parentNode).toggleClass('selected',this.clicked);}); /* add row selectors */
+ $('td:eq(0)', nRow).attr("title", "Click ID to select/deselect quote");
+ if (isNaN(quoteID)) {
+ noEditFields = [0,1,2,3]; /* all fields when adding a quote */
+ }
+ else {
+ noEditFields = [0,3]; /* id, timestamp */
+ }
+ /* apply no_edit id to noEditFields */
+ for (i=0; i<noEditFields.length; i++) {
+ $('td', nRow)[noEditFields[i]].setAttribute("id","no_edit");
+ }
+ return nRow;
+ },
+ "fnDrawCallback": function(oSettings) {
+ /* Apply the jEditable handlers to the table on all fields w/o the no_edit id */
+ $('#quotes_editor tbody td[id!="no_edit"]').editable( "/cgi-bin/koha/tools/quotes/quotes_ajax.pl", {
+ "submitdata" : function ( value, settings ) {
+ return {
+ "column" : oTable.fnGetPosition( this )[2],
+ "action" : "edit",
+ };
+ },
+ "height" : "14px",
+ "placeholder" : "Saving data...",
+ });
+ },
+ });
+ });
+
+ function fnClickAddQuote(e, node) {
+ if (e.charCode) {
+ /* some browsers only give charCode, so this will need to be */
+ /* fixed up to handle that */
+ console.log('charCode: '+e.charCode);
+ }
+ if (e.keyCode == 13) {
+ var quoteSource = $('#quoteSource').val();
+ var quoteText = $('#quoteText').val()
+ /* If passed a quote source, add the quote to the db */
+ if (quoteSource && quoteText) {
+ $.ajax({
+ url: "/cgi-bin/koha/tools/quotes/quotes_ajax.pl",
+ type: "POST",
+ data: {
+ "source" : quoteSource,
+ "text" : quoteText,
+ "action" : "add",
+ },
+ success: function(data){
+ var newQuote = data[0];
+ var aRow = oTable.fnUpdate(
+ newQuote,
+ node,
+ false,
+ false
+ );
+ oTable.fnPageChange( 'last' );
+ $('.add_quote_button').attr('onclick', 'fnClickAddRow()'); // re-enable add button
+ }
+ });
+ }
+ else {
+ alert('Please supply both the text and source of the quote before saving.');
+ }
+ }
+ else if (e.keyCode == 27) {
+ if (confirm('Are you sure you want to cancel adding this quote?')) {
+ oTable.fnDeleteRow(node);
+ }
+ else {
+ return;
+ }
+ }
+ }
+
+ function fnClickAddRow() {
+ $('.add_quote_button').removeAttr('onclick'); // disable add button once it has been clicked
+ var aRow = oTable.fnAddData(
+ [
+ 'NA', // this is hackish to fool the datatable sort routine into placing this row at the end of the list...
+ '<input id="quoteSource" type="text" style="height:14px; width:99%" onkeydown="fnClickAddQuote(event,this.parentNode.parentNode)"/>',
+ '<input id="quoteText" type="text" style="height:14px; width:99%" onkeydown="fnClickAddQuote(event,this.parentNode.parentNode)"/>',
+ '0000-00-00 00:00:00',
+ ],
+ false
+ );
+ oTable.fnPageChange( 'last' );
+ $('#quoteSource').focus();
+ }
+
+ function fnClickDeleteRow() {
+ var idsToDelete = oTable.$('.selected').map(function() {
+ return this.id;
+ }).get().join(', ');
+ if (!idsToDelete) {
+ alert('Please select a quote(s) by clicking the quote id(s) you desire to delete.');
+ }
+ else if (confirm('Are you sure you wish to delete quote(s) '+idsToDelete+'?')) {
+ oTable.$('.selected').each(function(){
+ var quoteID = $(this).attr('id');
+ $.ajax({
+ url: "/cgi-bin/koha/tools/quotes/quotes_ajax.pl",
+ type: "POST",
+ data: {
+ "id" : quoteID,
+ "action" : "delete",
+ },
+ /* Delete the row from the datatable */
+ success: function(){
+ oTable.fnDeleteRow(this);
+ oTable.fnReloadAjax(null, null, true);
+ }
+ });
+ });
+ }
+ else {
+ return;
+ }
+ }
+ //]]>
+ </script>
+</head>
+<body id="tools_quotes" class="tools">
+[% INCLUDE 'header.inc' %]
+[% INCLUDE 'cat-search.inc' %]
+
+<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> › <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> › Quote Editor</div>
+
+<div id="doc3" class="yui-t2">
+ <div id="bd">
+ <div id="yui-main">
+ <div class="yui-b">
+ [% INCLUDE 'quotes-toolbar.inc' %]
+ <h2>Quote editor</h2>
+ <table id="quotes_editor" style="float: left; width: 100%;">
+ <thead>
+ <tr>
+ <th><span style="cursor: help" onclick="event.stopPropagation();alert('Click on the quote\'s id to select or deselect the quote. Multiple quotes may be selected.');">ID</span></th>
+ <th>Source</th>
+ <th>Text</th>
+ <th>Last Displayed</th>
+<!-- <th>Actions</th>-->
+ </tr>
+ </thead>
+ <tbody>
+ <!-- tbody content is generated by DataTables -->
+ <tr>
+ <td></td>
+ <td></td>
+ <td>Loading data...</td>
+ <td></td>
+<!-- <td></td>-->
+ </tr>
+ </tbody>
+ </table>
+ <fieldset id="footer" class="action" style="height:25px;">
+ </fieldset>
+ </div>
+ </div>
+ <div class="yui-b noprint">
+ [% INCLUDE 'tools-menu.inc' %]
+ </div>
+</div>
+[% INCLUDE 'intranet-bottom.inc' %]
<dd>Schedule tasks to run</dd>
[% END %]
+ [% IF ( CAN_user_tools_edit_quotes ) %]
+ <dt><a href="/cgi-bin/koha/tools/quotes.pl">Edit Quotes for QOTD Feature</a></dt>
+ <dd>Quote editor for Quote-of-the-day feature in OPAC</dd>
+ [% END %]
</dl>
</div>
text-shadow: 1px 1px 0 #FFF;
}
+#daily-quote {
+ /*border-top : 1px solid #000000;*/
+ border : 1px solid #000000;
+ margin-top: 2px;
+ margin-bottom: 10px;
+ margin-left: 2px;
+ margin-right: 2px;
+ width: 300px;
+ text-align: center;
+ font-family: "Georgia","Palatino","Times New Roman",sans-serif;
+}
+
+#daily-quote h1 {
+ font-size: 18px;
+ font-weight: normal;
+ margin: 0;
+}
+
+#daily-quote div {
+ font-size: 12px;
+ margin: 5px;
+}
+
/* ## BABELTHEQUE ## */
/* Uncomment if babeltheque configuration no contains these lines */
/*
</div>
[% END %]
+ [% IF ( display_daily_quote && daily_quote ) %]
+ <div id="daily-quote" class="container"><h1>Quote of the Day</h1><div><span id="daily-quote-text">[% daily_quote.text %]</span><span id="daily-quote-sep"> ~ </span><span id="daily-quote-source">[% daily_quote.source %]</span></div></div>
+[% END %]
+
[% IF ( OpacMainUserBlock ) %]<div id="opacmainuserblock" class="container">[% OpacMainUserBlock %]</div>[% END %]
</div>
use C4::Output;
use C4::NewsChannels; # get_opac_news
use C4::Languages qw(getTranslatedLanguages accept_language);
+use C4::Koha qw( GetDailyQuote );
my $input = new CGI;
my $dbh = C4::Context->dbh;
my $all_koha_news = &GetNewsToDisplay($news_lang);
my $koha_news_count = scalar @$all_koha_news;
+my $quote = GetDailyQuote(); # other options are to pass in an exact quote id or select a random quote each pass... see perldoc C4::Koha
+
$template->param(
- koha_news => $all_koha_news,
- koha_news_count => $koha_news_count
+ koha_news => $all_koha_news,
+ koha_news_count => $koha_news_count,
+ display_daily_quote => C4::Context->preference('QuoteOfTheDay'),
+ daily_quote => $quote,
);
# If GoogleIndicTransliteration system preference is On Set paramter to load Google's javascript in OPAC search screens
--- /dev/null
+#!/usr/bin/perl
+
+# Copyright 2012 Foundations Bible College Inc.
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use CGI;
+use autouse 'Data::Dumper' => qw(Dumper);
+
+use C4::Auth;
+use C4::Koha;
+use C4::Context;
+use C4::Output;
+
+my $cgi = new CGI;
+
+my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+ {
+ template_name => "tools/quotes.tt",
+ query => $cgi,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { tools => 'edit_quotes' },
+ debug => 1,
+ }
+);
+
+output_html_with_http_headers $cgi, $cookie, $template->output;
--- /dev/null
+#!/usr/bin/perl
+
+# Copyright 2012 Foundations Bible College Inc.
+#
+# This file is part of Koha.
+#
+# Koha is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2 of the License, or (at your option) any later
+# version.
+#
+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+use strict;
+use warnings;
+
+use CGI;
+use JSON;
+use autouse 'Data::Dumper' => qw(Dumper);
+
+use C4::Auth;
+use C4::Context;
+
+my $cgi = CGI->new;
+my $dbh = C4::Context->dbh;
+my $sort_columns = ["id", "source", "text", "timestamp"];
+
+my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
+ {
+ template_name => "",
+ query => $cgi,
+ type => "intranet",
+ authnotrequired => 0,
+ flagsrequired => { tools => 'edit_quotes' },
+ debug => 1,
+ }
+);
+
+# NOTE: This is a collection of ajax functions for use with tools/quotes.pl
+
+my $params = $cgi->Vars; # NOTE: Multivalue parameters NOT allowed!!
+
+print $cgi->header('application/json');
+
+if ($params->{'action'} eq 'add') {
+ my $sth = $dbh->prepare('INSERT INTO quotes (source, text) VALUES (?, ?);');
+ $sth->execute($params->{'source'}, $params->{'text'});
+ if ($sth->err) {
+ warn sprintf('Database returned the following error: %s', $sth->errstr);
+ exit 0;
+ }
+ my $new_quote_id = $dbh->{q{mysql_insertid}}; # ALERT: mysqlism here
+ $sth = $dbh->prepare('SELECT * FROM quotes WHERE id = ?;');
+ $sth->execute($new_quote_id);
+ print to_json($sth->fetchall_arrayref);
+ exit 1;
+}
+elsif ($params->{'action'} eq 'edit') {
+ my $editable_columns = [qw(source text)]; # pay attention to element order; these columns match the quotes table columns
+ my $sth = $dbh->prepare("UPDATE quotes SET $editable_columns->[$params->{'column'}-1] = ? WHERE id = ?;");
+ $sth->execute($params->{'value'}, $params->{'id'});
+ if ($sth->err) {
+ warn sprintf('Database returned the following error: %s', $sth->errstr);
+ exit 0;
+ }
+ print $sth->fetchrow_array();
+ exit 1;
+}
+elsif ($params->{'action'} eq 'delete') {
+ my $sth = $dbh->prepare("DELETE FROM quotes WHERE id = ?;");
+ $sth->execute($params->{'id'});
+ if ($sth->err) {
+ warn sprintf('Database returned the following error: %s', $sth->errstr);
+ exit 0;
+ }
+ exit 1;
+}
+else {
+ my $aaData = [];
+ my $iTotalRecords = '';
+ my $sth = '';
+
+ if (my $filter = $params->{'sSearch'}) {
+ # This seems a bit brute force and ungraceful, but it provides a very general, simple search on all fields
+ my $like = " id LIKE \"%$filter%\" OR source LIKE \"%$filter%\" OR text LIKE \"%$filter%\" OR timestamp LIKE \"%$filter%\"";
+ $iTotalRecords = $dbh->selectrow_array("SELECT count(*) FROM quotes WHERE $like;");
+ $sth = $dbh->prepare("SELECT * FROM quotes;");
+ }
+ else {
+ $iTotalRecords = $dbh->selectrow_array('SELECT count(*) FROM quotes;');
+ $sth = $dbh->prepare("SELECT * FROM quotes;");
+ }
+
+ $sth->execute();
+ if ($sth->err) {
+ warn sprintf('Database returned the following error: %s', $sth->errstr);
+ exit 0;
+ }
+
+ $aaData = $sth->fetchall_arrayref;
+ my $iTotalDisplayRecords = $iTotalRecords; # no filtering happening here
+
+
+ print to_json({
+ iTotalRecords => $iTotalRecords,
+ iTotalDisplayRecords=> $iTotalDisplayRecords,
+ sEcho => $params->{'sEcho'},
+ aaData => $aaData,
+ });
+}