Browse Source

Bug 7977: Quote-of-the-day (QOTD) Feature for OPAC

This feature will add the option of displaying a select quote
for the day on the OPAC homepage. It will include the addition
of a QOTD editor in the tools section of the staff interface
which will allow the addition, editing, and deletion of quotes.
A single system preference will enable/disable the display of
the QOTD on the OPAC homepage. A new granular permission will
also be added to conrol user access to the QOTD editor tool.

Possible extentions to this would be code to allow alternate
quote selection algorithms to be added to vary how the currently
displayed quote is selected from the table of quotes.

This patch is a squash of the following work:

--Adding quotes table to kohastructure.sql and updatedatabase.pl

Note: This patch is intended for a MySQL based installation only.
That means that it includes backticks because that is what is required
at this point in history to install Koha correctly on a MySQL based
installation.

Feel free to port this over to the Pg stuff in the data/Pg directory.

--Adding system preference to control display of QOTD on OPAC main page
--Adding sample quote data

These quotes are taken from various US presidents. I'm not sure these
are applicable to the rest of the world, so I'm leaving it to translators
and others to add sample quote data for other languages.

--Adding edit_quotes user permissions
--Squash with other db related patches in this series
--Adding quotes editor pages to tools
--Adding QOTD editor link to tools homepage
--Integration of DataTables into QOTD Editor
--Impleminting jEditable into the quote editor
--Adding delete and add option to editor
--Fixing OPAC display so the QOTD div does not show if no quote is returned
--Also removing useless code from tools/quotes.pl
--Adding spans around QOTD foo in opac-main.tt
--Also fixing quote selection logic to accomodate the possibility of
    a single quote in the db a litte better.
--Changing timestamp column header to a more user-friendly 'Last Displayed'
--Fixing bug in quote selection logic. This bug caused a situation where
    when the table had only a single quote with an id greater than 1 in it,
    no quote would be selected.
--Fixing up sorting in the quote editor table. --jcamins
--Adding span element to quote separator --jcamins
--Overriding the default empty table message supplied by datatables-strings.inc
--Adds missing page heading
--Adds beginning of click-for-help elements.
--Refactors delete functionality to allow selecting of quotes to delete,
    enabling multi-delete.
--Refactors saving added quote functionality so that striking <Enter>
    saves the new quote.
--Refactors canceling aded quote functionality so that striking <Esc>
    cancels the new quote.
--Removing debug console.log statements
--Implementng the YUI button widget/toolbar used on other pages.
--Adds a 5px radius to all YUI buttons to bring them into
    conformity with the general trend toward rounded corners
--Fixes capitalization in quote editor
--Implements improvements suggested by jcamins and oleonard
--Adds DataTables Plugin dataTables.fnReloadAjax.js

Signed-off-by: Jared Camins-Esakov <jcamins@cpbibliography.com>
Signed-off-by: Mason James <mtj@kohaaloha.com>
3.10.x
Chris Nighswonger 11 years ago
committed by Paul Poulain
parent
commit
eb7e930eea
  1. 80
      C4/Koha.pm
  2. 1
      installer/data/mysql/de-DE/mandatory/userpermissions.sql
  3. 1
      installer/data/mysql/en/mandatory/userpermissions.sql
  4. 34
      installer/data/mysql/en/optional/sample_quotes.sql
  5. 1
      installer/data/mysql/en/optional/sample_quotes.txt
  6. 1
      installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql
  7. 1
      installer/data/mysql/it-IT/necessari/userpermissions.sql
  8. 13
      installer/data/mysql/kohastructure.sql
  9. 1
      installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql
  10. 1
      installer/data/mysql/pl-PL/mandatory/userpermissions.sql
  11. 1
      installer/data/mysql/ru-RU/mandatory/permissions_and_user_flags.sql
  12. 1
      installer/data/mysql/sysprefs.sql
  13. 1
      installer/data/mysql/uk-UA/mandatory/permissions_and_user_flags.sql
  14. 23
      installer/data/mysql/updatedatabase.pl
  15. 23
      koha-tmpl/intranet-tmpl/prog/en/css/datatables.css
  16. 8
      koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css
  17. 48
      koha-tmpl/intranet-tmpl/prog/en/includes/quotes-toolbar.inc
  18. 3
      koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc
  19. 50
      koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/dataTables.fnReloadAjax.js
  20. 8
      koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref
  21. 205
      koha-tmpl/intranet-tmpl/prog/en/modules/tools/quotes.tt
  22. 4
      koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt
  23. 23
      koha-tmpl/opac-tmpl/prog/en/css/opac.css
  24. 4
      koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt
  25. 9
      opac/opac-main.pl
  26. 44
      tools/quotes.pl
  27. 116
      tools/quotes/quotes_ajax.pl

80
C4/Koha.pm

@ -22,10 +22,15 @@ package C4::Koha;
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;
@ -67,6 +72,7 @@ BEGIN {
$DEBUG
);
$DEBUG = 0;
@EXPORT_OK = qw( GetDailyQuote );
}
# expensive functions
@ -1301,6 +1307,78 @@ sub GetNormalizedOCLCNumber {
}
}
=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]*)/;

1
installer/data/mysql/de-DE/mandatory/userpermissions.sql

@ -22,6 +22,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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'),

1
installer/data/mysql/en/mandatory/userpermissions.sql

@ -22,6 +22,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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'),

34
installer/data/mysql/en/optional/sample_quotes.sql

@ -0,0 +1,34 @@
/*!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 */;

1
installer/data/mysql/en/optional/sample_quotes.txt

@ -0,0 +1 @@
Sample Quotes

1
installer/data/mysql/fr-FR/1-Obligatoire/userpermissions.sql

@ -12,6 +12,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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'),

1
installer/data/mysql/it-IT/necessari/userpermissions.sql

@ -24,6 +24,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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'),

13
installer/data/mysql/kohastructure.sql

@ -2831,6 +2831,19 @@ CREATE TABLE ratings (
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 */;

1
installer/data/mysql/nb-NO/1-Obligatorisk/userpermissions.sql

@ -43,6 +43,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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'),

1
installer/data/mysql/pl-PL/mandatory/userpermissions.sql

@ -22,6 +22,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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'),

1
installer/data/mysql/ru-RU/mandatory/permissions_and_user_flags.sql

@ -46,6 +46,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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', 'Заготовка МАРК-записей в хранилище'),

1
installer/data/mysql/sysprefs.sql

@ -95,6 +95,7 @@ INSERT INTO `systempreferences` (variable,value,explanation,options,type) VALUES
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');

1
installer/data/mysql/uk-UA/mandatory/permissions_and_user_flags.sql

@ -46,6 +46,7 @@ INSERT INTO permissions (module_bit, code, description) VALUES
(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', 'Заготівля МАРК-записів у сховище'),

23
installer/data/mysql/updatedatabase.pl

@ -5246,6 +5246,29 @@ if ( C4::Context->preference("Version") < TransformToNum($DBversion) ) {
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)

23
koha-tmpl/intranet-tmpl/prog/en/css/datatables.css

@ -85,25 +85,25 @@ div.dataTables_paginate {
.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;
}
@ -175,6 +175,21 @@ div.dataTables_paginate.paging_four_button {
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 {

8
koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css

@ -26,6 +26,14 @@ a:hover, a:active {
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;
}

48
koha-tmpl/intranet-tmpl/prog/en/includes/quotes-toolbar.inc

@ -0,0 +1,48 @@
<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 &lt;Enter&gt; to save changes.</span>
</ul>
</div>

3
koha-tmpl/intranet-tmpl/prog/en/includes/tools-menu.inc

@ -91,4 +91,7 @@
[% 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>

50
koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/dataTables.fnReloadAjax.js

@ -0,0 +1,50 @@
$.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();

8
koha-tmpl/intranet-tmpl/prog/en/modules/admin/preferences/opac.pref

@ -330,7 +330,13 @@ OPAC:
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

205
koha-tmpl/intranet-tmpl/prog/en/modules/tools/quotes.tt

@ -0,0 +1,205 @@
[% INCLUDE 'doc-head-open.inc' %]
<title>Koha &rsaquo; Tools &rsaquo; 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> &rsaquo; <a href="/cgi-bin/koha/tools/tools-home.pl">Tools</a> &rsaquo; 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' %]

4
koha-tmpl/intranet-tmpl/prog/en/modules/tools/tools-home.tt

@ -92,6 +92,10 @@
<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>

23
koha-tmpl/opac-tmpl/prog/en/css/opac.css

@ -2405,6 +2405,29 @@ span.sep {
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 */
/*

4
koha-tmpl/opac-tmpl/prog/en/modules/opac-main.tt

@ -35,6 +35,10 @@
</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>

9
opac/opac-main.pl

@ -23,6 +23,7 @@ use C4::Auth; # get_template_and_user
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;
@ -50,9 +51,13 @@ my ($theme, $news_lang) = C4::Templates::themelanguage(C4::Context->config('opac
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

44
tools/quotes.pl

@ -0,0 +1,44 @@
#!/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;

116
tools/quotes/quotes_ajax.pl

@ -0,0 +1,116 @@
#!/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,
});
}
Loading…
Cancel
Save