From 07e85842f6876a23d807c8758189cc50cdebc128 Mon Sep 17 00:00:00 2001 From: Salvador Zaragoza Rubio <salvazm@masmedios.com> Date: Fri, 4 Mar 2011 10:05:34 +0100 Subject: [PATCH] Bug 5478 - Automate MARC framework import/export Content-Type: text/plain; charset="utf-8" Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section, exporting the tables marc_tag_structure, marc_subfield_structure to excel-xml/ods spreadsheet or importing the spreadsheet to marc_tag_structure, marc_subfield_structure mysql tables, overwriting the data. Bug 5478 - Automate MARC framework import/export Add delete functionality. Bug 5478 - Automate MARC framework import/export Fix id on default form --- C4/ImportExportFramework.pm | 986 ++++++++++++++++++++ admin/import_export_framework.pl | 68 ++ .../intranet-tmpl/prog/en/css/staff-global.css | 48 + .../prog/en/modules/admin/biblio_framework.tmpl | 141 +++ 4 files changed, 1243 insertions(+), 0 deletions(-) create mode 100755 C4/ImportExportFramework.pm create mode 100755 admin/import_export_framework.pl mode change 100644 => 100755 koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css mode change 100644 => 100755 koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl diff --git a/C4/ImportExportFramework.pm b/C4/ImportExportFramework.pm new file mode 100755 index 0000000..43900ac --- /dev/null +++ b/C4/ImportExportFramework.pm @@ -0,0 +1,986 @@ +package C4::ImportExportFramework; + +# Copyright 2010-2011 MASmedios.com y Ministerio de Cultura +# +# 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 XML::LibXML; +use XML::LibXML::XPathContext; +use Digest::MD5 qw(md5_base64); +use POSIX qw(strftime); + +use C4::Context; +use C4::Debug; + + +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); + +BEGIN { + $VERSION = 3.03; # set version for version checking + require Exporter; + @ISA = qw(Exporter); + @EXPORT = qw( + &ExportFramework + &ImportFramework + &createODS + ); +} + + +use constant XMLSTR => '<?xml version="1.0" encoding="UTF-8"?> +<?mso-application progid="Excel.Sheet"?> +<Workbook + xmlns:x="urn:schemas-microsoft-com:office:excel" + xmlns="urn:schemas-microsoft-com:office:spreadsheet" + xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"> + +<Styles> + <Style ss:ID="Default" ss:Name="Normal"> + <Alignment ss:Vertical="Bottom"/> + <Borders/> + <Font/> + <Interior/> + <NumberFormat/> + <Protection/> + </Style> + <Style ss:ID="s27"> + <Font x:Family="Swiss" ss:Color="#0000FF" ss:Bold="1"/> + </Style> + <Style ss:ID="s21"> + <NumberFormat ss:Format="yyyy\-mm\-dd"/> + </Style> + <Style ss:ID="s22"> + <NumberFormat ss:Format="yyyy\-mm\-dd\ hh:mm:ss"/> + </Style> + <Style ss:ID="s23"> + <NumberFormat ss:Format="hh:mm:ss"/> + </Style> +</Styles> + +</Workbook> +'; + + +use constant ODSSTR => '<?xml version="1.0" encoding="UTF-8"?> +<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0"> +<office:scripts/> +<office:font-face-decls/> +<office:automatic-styles/> +</office:document-content>'; + + +use constant ODS_STYLES_STR => '<?xml version="1.0" encoding="UTF-8"?> +<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" office:version="1.0"> +<office:font-face-decls></office:font-face-decls> +<office:styles></office:styles> +<office:automatic-styles></office:automatic-styles> +<office:master-styles></office:master-styles> +</office:document-styles>'; + + +use constant ODS_SETTINGS_STR => '<?xml version="1.0" encoding="UTF-8"?> +<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.0"><office:settings> +<config:config-item-set config:name="ooo:view-settings"> +<config:config-item config:name="VisibleAreaTop" config:type="int">0</config:config-item> +<config:config-item config:name="VisibleAreaLeft" config:type="int">0</config:config-item> +<config:config-item config:name="VisibleAreaWidth" config:type="int">2000</config:config-item> +<config:config-item config:name="VisibleAreaHeight" config:type="int">900</config:config-item> +<config:config-item-map-indexed config:name="Views"><config:config-item-map-entry> +<config:config-item config:name="ViewId" config:type="string">View1</config:config-item> +<config:config-item-map-named config:name="Tables"> +<config:config-item-map-entry config:name="Sheet1"><config:config-item config:name="CursorPositionX" config:type="int">0</config:config-item><config:config-item config:name="CursorPositionY" config:type="int">1</config:config-item><config:config-item config:name="HorizontalSplitMode" config:type="short">0</config:config-item><config:config-item config:name="VerticalSplitMode" config:type="short">0</config:config-item><config:config-item config:name="HorizontalSplitPosition" config:type="int">0</config:config-item><config:config-item config:name="VerticalSplitPosition" config:type="int">0</config:config-item><config:config-item config:name="ActiveSplitRange" config:type="short">2</config:config-item><config:config-item config:name="PositionLeft" config:type="int">0</config:config-item><config:config-item config:name="PositionRight" config:type="int">0</config:config-item><config:config-item config:name="PositionTop" config:type="int">0</config:config-item><config:config-item config:name="PositionBottom" config:type="int">0</config:config-item> +</config:config-item-map-entry> +</config:config-item-map-named> +<config:config-item config:name="ActiveTable" config:type="string">Sheet1</config:config-item> +<config:config-item config:name="HorizontalScrollbarWidth" config:type="int">270</config:config-item> +<config:config-item config:name="ZoomType" config:type="short">0</config:config-item> +<config:config-item config:name="ZoomValue" config:type="int">100</config:config-item> +<config:config-item config:name="PageViewZoomValue" config:type="int">50</config:config-item> +<config:config-item config:name="ShowPageBreakPreview" config:type="boolean">false</config:config-item> +<config:config-item config:name="ShowZeroValues" config:type="boolean">true</config:config-item> +<config:config-item config:name="ShowNotes" config:type="boolean">true</config:config-item> +<config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item> +<config:config-item config:name="GridColor" config:type="long">12632256</config:config-item> +<config:config-item config:name="ShowPageBreaks" config:type="boolean">true</config:config-item> +<config:config-item config:name="HasColumnRowHeaders" config:type="boolean">true</config:config-item> +<config:config-item config:name="HasSheetTabs" config:type="boolean">true</config:config-item> +<config:config-item config:name="IsOutlineSymbolsSet" config:type="boolean">true</config:config-item> +<config:config-item config:name="IsSnapToRaster" config:type="boolean">false</config:config-item> +<config:config-item config:name="RasterIsVisible" config:type="boolean">false</config:config-item> +<config:config-item config:name="IsRasterAxisSynchronized" config:type="boolean">true</config:config-item></config:config-item-map-entry></config:config-item-map-indexed> +</config:config-item-set> +<config:config-item-set config:name="ooo:configuration-settings"> +<config:config-item config:name="ShowZeroValues" config:type="boolean">true</config:config-item> +<config:config-item config:name="ShowNotes" config:type="boolean">true</config:config-item> +<config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item> +<config:config-item config:name="GridColor" config:type="long">12632256</config:config-item> +<config:config-item config:name="ShowPageBreaks" config:type="boolean">true</config:config-item> +<config:config-item config:name="LinkUpdateMode" config:type="short">3</config:config-item> +<config:config-item config:name="HasColumnRowHeaders" config:type="boolean">true</config:config-item> +<config:config-item config:name="HasSheetTabs" config:type="boolean">true</config:config-item> +<config:config-item config:name="IsOutlineSymbolsSet" config:type="boolean">true</config:config-item> +<config:config-item config:name="IsSnapToRaster" config:type="boolean">false</config:config-item> +<config:config-item config:name="RasterIsVisible" config:type="boolean">false</config:config-item> +<config:config-item config:name="IsRasterAxisSynchronized" config:type="boolean">true</config:config-item> +<config:config-item config:name="AutoCalculate" config:type="boolean">true</config:config-item> +<config:config-item config:name="PrinterName" config:type="string">Generic Printer</config:config-item> +<config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item> +<config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item> +<config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item> +<config:config-item config:name="UpdateFromTemplate" config:type="boolean">false</config:config-item> +<config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item> +<config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item> +</config:config-item-set> +</office:settings></office:document-settings>'; + + +use constant ODS_MANIFEST_STR => '<?xml version="1.0" encoding="UTF-8"?> +<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"> + <manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.spreadsheet" manifest:full-path="/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/statusbar/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/accelerator/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/floater/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/popupmenu/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/progressbar/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/menubar/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/toolbar/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/images/Bitmaps/"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Configurations2/images/"/> + <manifest:file-entry manifest:media-type="application/vnd.sun.xml.ui.configuration" manifest:full-path="Configurations2/"/> + <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/> + <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/> + <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml"/> + <manifest:file-entry manifest:media-type="" manifest:full-path="Thumbnails/"/> + <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml"/> +</manifest:manifest>'; + + +=head1 NAME + +C4::ImportExportFramework - Import/Export Framework to Excel-xml/ODS Module Functions + +=head1 SYNOPSIS + + use C4::ImportExportFramework; + +=head1 DESCRIPTION + +Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section + +Module to Import/Export Framework to Excel-xml/ODS on intranet administration - MARC Frameworks section +exporting the tables marc_tag_structure, marc_subfield_structure to excel-xml/ods or viceversa + +Functions for handling import/export. + + +=head1 SUBROUTINES + + + +=head2 ExportFramework + +Export all the information of a Framework to an excel "xml" file or OpenDocument SpreadSheet "ods" file. + +return : +succes + +=cut + +sub ExportFramework +{ + my ($frameworkcode, $xmlStrRef, $mode) = @_; + + my $dbh = C4::Context->dbh; + if ($dbh) { + my $dom; + my $root; + my $elementSS; + eval { + my $parser = XML::LibXML->new(); + $dom = $parser->parse_string(($mode && $mode eq 'ods')?ODSSTR:XMLSTR); + if ($dom) { + $root = $dom->documentElement(); + if ($mode && $mode eq 'ods') { + my $elementBody = $dom->createElement('office:body'); + $root->appendChild($elementBody); + $elementSS = $dom->createElement('office:spreadsheet'); + $elementBody->appendChild($elementSS); + } + } + }; + if ($@) { + $debug and warn "Error ExportFramework $@\n"; + return 0; + } + if (_export_table('marc_tag_structure', $dbh, $dom, ($mode && $mode eq 'ods')?$elementSS:$root, $frameworkcode, $mode)) { + if (_export_table('marc_subfield_structure', $dbh, $dom, ($mode && $mode eq 'ods')?$elementSS:$root, $frameworkcode, $mode)) { + $$xmlStrRef = $dom->toString(1); + return 1; + } + } + } + return 0; +}#ExportFramework + + + + +# Export all the data from a mysql table to an spreadsheet. +sub _export_table +{ + my ($table, $dbh, $dom, $root, $frameworkcode, $mode) = @_; + + if ($mode && $mode eq 'ods') { + _export_table_ods($table, $dbh, $dom, $root, $frameworkcode); + } else { + _export_table_excel($table, $dbh, $dom, $root, $frameworkcode); + } +} + + +# Export the mysql table to an ods file +sub _export_table_ods +{ + my ($table, $dbh, $dom, $root, $frameworkcode) = @_; + + eval { + my $elementTable = $dom->createElement('table:table'); + $elementTable->setAttribute('table:name', $table); + $elementTable->setAttribute('table:print', 'false'); + $root->appendChild($elementTable); + my $elementRow = $dom->createElement('table:table-row'); + $elementTable->appendChild($elementRow); + + my $elementCell; + my $elementData; + # First row with the name of the columns + my $query = 'SHOW COLUMNS FROM ' . $table; + my $sth = $dbh->prepare($query); + $sth->execute(); + my @fields = (); + while (my $hashRef = $sth->fetchrow_hashref) { + $elementCell = $dom->createElement('table:table-cell'); + $elementCell->setAttribute('office:value-type', 'string'); + $elementCell->setAttribute('office:value', $hashRef->{Field}); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('text:p'); + $elementCell->appendChild($elementData); + $elementData->appendTextNode($hashRef->{Field}); + push @fields, {name => $hashRef->{Field}, type => ($hashRef->{Type} =~ /int/i)?'float':'string'}; + } + # Populate rows with the data from mysql + $query = 'SELECT * FROM ' . $table . ' WHERE frameworkcode=?'; + $sth = $dbh->prepare($query); + $sth->execute($frameworkcode); + my $data; + while (my $hashRef = $sth->fetchrow_hashref) { + $elementRow = $dom->createElement('table:table-row'); + $elementTable->appendChild($elementRow); + for (@fields) { + $data = $hashRef->{$_->{name}}; + if ($_->{type} eq 'float' && !defined($data)) { + $data = '0'; + } elsif ($_->{type} eq 'string' && (!$data && $data ne '0')) { + $data = '#'; + } + $data = _parseContent2Xml($data) if ($_->{type} eq 'string'); + $elementCell = $dom->createElement('table:table-cell'); + $elementCell->setAttribute('office:value-type', $_->{type}); + $elementCell->setAttribute('office:value', $data); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('text:p'); + $elementCell->appendChild($elementData); + $elementData->appendTextNode($data); + } + } + }; + if ($@) { + $debug and warn "Error _export_table_ods $@\n"; + return 0; + } + return 1; +}#_export_table_ods + + +# Export the mysql table to an excel-xml (openoffice/libreoffice compatible) file +sub _export_table_excel +{ + my ($table, $dbh, $dom, $root, $frameworkcode) = @_; + + eval { + my $elementWS = $dom->createElement('Worksheet'); + $elementWS->setAttribute('ss:Name', $table); + $root->appendChild($elementWS); + my $elementTable = $dom->createElement('ss:Table'); + $elementWS->appendChild($elementTable); + my $elementRow = $dom->createElement('ss:Row'); + $elementTable->appendChild($elementRow); + + # First row with the name of the columns + my $elementCell; + my $elementData; + my $query = 'SHOW COLUMNS FROM ' . $table; + my $sth = $dbh->prepare($query); + $sth->execute(); + my @fields = (); + while (my $hashRef = $sth->fetchrow_hashref) { + $elementCell = $dom->createElement('ss:Cell'); + $elementCell->setAttribute('ss:StyleID', 's27'); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('ss:Data'); + $elementData->setAttribute('ss:Type', 'String'); + $elementCell->appendChild($elementData); + $elementData->appendTextNode($hashRef->{Field}); + push @fields, {name => $hashRef->{Field}, type => ($hashRef->{Type} =~ /int/i)?'Number':'String'}; + } + # Populate rows with the data from mysql + $query = 'SELECT * FROM ' . $table . ' WHERE frameworkcode=?'; + $sth = $dbh->prepare($query); + $sth->execute($frameworkcode); + my $data; + while (my $hashRef = $sth->fetchrow_hashref) { + $elementRow = $dom->createElement('ss:Row'); + $elementTable->appendChild($elementRow); + for (@fields) { + $elementCell = $dom->createElement('ss:Cell'); + $elementRow->appendChild($elementCell); + $elementData = $dom->createElement('ss:Data'); + $elementData->setAttribute('ss:Type', $_->{type}); + $elementCell->appendChild($elementData); + $data = $hashRef->{$_->{name}}; + if ($_->{type} eq 'Number' && !defined($data)) { + $data = '0'; + } elsif ($_->{type} eq 'String' && (!$data && $data ne '0')) { + $data = '#'; + } + $elementData->appendTextNode(($_->{type} eq 'String')?_parseContent2Xml($data):$data); + } + } + }; + if ($@) { + $debug and warn "Error _export_table_excel $@\n"; + return 0; + } + return 1; +}#_export_table_excel + + + + + + + +# Format chars problematics to a correct format for xml. +sub _parseContent2Xml +{ + my $content = shift; + + $content =~ s/\&(?![a-zA-Z#0-9]{1,4};)/&/g; + $content =~ s/</</g; + $content =~ s/>/>/g; + return $content; +}#_parseContent2Xml + + +# Get the tmp directory on the system +sub _getTmp +{ + my $tmp = '/tmp'; + if ($ENV{'TMP'} && -d $ENV{'TMP'}) { + $tmp = $ENV{'TMP'}; + } elsif ($ENV{'TMPDIR'} && -d $ENV{'TMPDIR'}) { + $tmp = $ENV{'TMPDIR'}; + } elsif ($ENV{'TEMP'} && -d $ENV{'TEMP'}) { + $tmp = $ENV{'TEMP'}; + } + return $tmp; +}#_getTmp + + +# Create our tempdir directory for the ods process +sub _createTmpDir +{ + my $tmp = shift; + + my $tempdir = (-d $tmp)?$tmp . '/':'./'; + $tempdir .= 'tmp_ods_' . Digest::MD5::md5_hex(Digest::MD5::md5_hex(time().{}.rand().{}.$$)); + eval { + mkdir $tempdir; + }; + if ($@) { + return undef; + } else { + return $tempdir; + } +}#_createTmpDir + +=head2 createODS + +Creates a temporary directory to create the ods file and read it to store its content in a string. + +return : +success + +=cut + +sub createODS +{ + my ($strContent, $lang, $strODSRef) = @_; + + my $tmp = _getTmp(); + my $tempModule = 1; + my $tempdir; + eval { + require File::Temp; + import File::Temp qw/ tempfile tempdir /; + $tempdir = tempdir ( 'tmp_ods_' . $$ . '_XXXXXXXX', DIR => (-d $tmp)?$tmp:'.', CLEANUP => 1); + }; + if ($@) { + $tempModule = 0; + $tempdir = _createTmpDir($tmp); + } + if ($tempdir) { + # populate tempdir directory with the ods elements + eval { + if (open(OUT, "> $tempdir/content.xml")) { + print OUT $strContent; + close(OUT); + } + if (open(OUT, "> $tempdir/mimetype")) { + print OUT 'application/vnd.oasis.opendocument.spreadsheet'; + close(OUT); + } + if (open(OUT, "> $tempdir/meta.xml")) { + print OUT _getMeta($lang); + close(OUT); + } + if (open(OUT, "> $tempdir/styles.xml")) { + print OUT ODS_STYLES_STR; + close(OUT); + } + if (open(OUT, "> $tempdir/settings.xml")) { + print OUT ODS_SETTINGS_STR; + close(OUT); + } + mkdir($tempdir.'/META-INF/'); + mkdir($tempdir.'/Configurations2/'); + mkdir($tempdir.'/Configurations2/acceleator/'); + mkdir($tempdir.'/Configurations2/images/'); + mkdir($tempdir.'/Configurations2/popupmenu/'); + mkdir($tempdir.'/Configurations2/statusbar/'); + mkdir($tempdir.'/Configurations2/floater/'); + mkdir($tempdir.'/Configurations2/menubar/'); + mkdir($tempdir.'/Configurations2/progressbar/'); + mkdir($tempdir.'/Configurations2/toolbar/'); + if (open(OUT, "> $tempdir/META-INF/manifest.xml")) { + print OUT ODS_MANIFEST_STR; + close(OUT); + } + }; + if ($@) { + $debug and warn "Error createODS $@\n"; + } else { + # create ods file from tempdir directory + eval { + require Archive::Zip; + import Archive::Zip qw( :ERROR_CODES :CONSTANTS ); + my $zip = Archive::Zip->new(); + $zip->addTree( $tempdir, '' ); + $zip->writeToFileNamed('new.ods'); + }; + if ($@) { + system("cd $tempdir && zip -r new.ods ./"); + } + my $ok = 0; + # read ods file and return as a string + if (-f "$tempdir/new.ods") { + if (open (MYFILE, "$tempdir/new.ods")) { + binmode MYFILE; + my $buffer; + while (read (MYFILE, $buffer, 65536)) { + $$strODSRef .= $buffer; + } + close(MYFILE); + $ok = 1; + } + } + # delete tempdir directory + if (!$tempModule && $tempdir) { + eval { + require File::Path; + import File::Temp qw/ rmtree /; + rmtree($tempdir); + }; + if ($@) { + system("rm -rf $tempdir"); + } + } + return 1 if ($ok); + } + } + return 0; +}#createODS + + +# return Meta content for ods file +sub _getMeta +{ + my $lang = shift; + + my $myDate = strftime ("%Y-%m-%dT%H:%M:%S", localtime(time())); + my $meta = '<?xml version="1.0" encoding="UTF-8"?> + <office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.0"> + <office:meta> + <meta:generator>ods-php</meta:generator> + <meta:creation-date>' . $myDate . '</meta:creation-date> + <dc:date>' . $myDate . '</dc:date> + <dc:language>' . $lang . '</dc:language> + <meta:editing-cycles>2</meta:editing-cycles> + <meta:editing-duration>PT15S</meta:editing-duration> + <meta:user-defined meta:name="Info 1"/> + <meta:user-defined meta:name="Info 2"/> + <meta:user-defined meta:name="Info 3"/> + <meta:user-defined meta:name="Info 4"/> + </office:meta> + </office:document-meta>'; + return $meta; +}#_getMeta + + +=head2 ImportFramework + +Import all the information of a Framework from a excel-xml/ods file. + +return : +success + +=cut + +sub ImportFramework +{ + my ($filename, $frameworkcode, $deleteFilename) = @_; + + my $tempdir; + my $ok = -1; + my $dbh = C4::Context->dbh; + if (-r $filename && $dbh) { + my $extension = ''; + if ($filename =~ /\.(ods|xml)$/i) { + $extension = lc($1); + } else { + unlink ($filename) if ($deleteFilename); + return -1; + } + if ($extension eq 'ods') { + ($tempdir, $filename) = _openODS($filename, $deleteFilename); + } + if ($filename) { + eval { + my $parser = XML::LibXML->new(); + my $dom = $parser->parse_file($filename); + if ($dom) { + my $element; + my $root = $dom->documentElement(); + my $numDeleted = 0; + my $numDeletedAux = 0; + if (($numDeletedAux = _import_table($dbh, 'marc_tag_structure', $frameworkcode, $dom, ['frameworkcode', 'tagfield'], $extension)) >= 0) { + $numDeleted += $numDeletedAux if ($numDeletedAux > 0); + if (($numDeletedAux = _import_table($dbh, 'marc_subfield_structure', $frameworkcode, $dom, ['frameworkcode', 'tagfield', 'tagsubfield'], $extension)) >= 0) { + $numDeleted += $numDeletedAux if ($numDeletedAux > 0); + $ok = ($numDeleted > 0)?$numDeleted:0; + } + } + } else { + $debug and warn "Error ImportFramework couldn't create dom\n"; + } + }; + if ($@) { + $debug and warn "Error ImportFramework $@\n"; + } + } + unlink ($filename) if ($deleteFilename); + } else { + $debug and warn "Error ImportFramework no conex to database or not readeable $filename\n"; + } + if ($deleteFilename && $tempdir && -d $tempdir && -w $tempdir) { + eval { + require File::Path; + import File::Temp qw/ rmtree /; + rmtree($tempdir); + }; + if ($@) { + system("rm -rf $tempdir"); + } + } + return $ok; +}#ImportFramework + + +# Open (uncompress) ods file and return the content.xml file +sub _openODS +{ + my ($filename, $deleteFilename) = @_; + + my $tmp = _getTmp(); + my $tempModule = 1; + my $tempdir; + eval { + require File::Temp; + import File::Temp qw/ tempfile tempdir /; + $tempdir = tempdir ( 'tmp_ods_' . $$ . '_XXXXXXXX', DIR => (-d $tmp)?$tmp:'.', CLEANUP => 0); + }; + if ($@) { + $tempModule = 0; + $tempdir = _createTmpDir($tmp); + } + if ($tempdir) { + eval { + require Archive::Zip; + import Archive::Zip qw( :ERROR_CODES :CONSTANTS ); + my $zip = Archive::Zip->new(); + $zip->extractTree( $filename, $tempdir ); + }; + if ($@) { + system("unzip $filename -d $tempdir"); + } + if (-f "$tempdir/content.xml") { + unlink ($filename) if ($deleteFilename); + return ($tempdir, "$tempdir/content.xml"); + } + } + unlink ($filename) if ($deleteFilename); + return ($tempdir, undef); +}#_openODS + + + +# Check the table and columns corresponds with worksheet +sub _check_validity_worksheet +{ + my ($dbh, $table, $nodeFields, $fieldsA, $format) = @_; + + my $ret = 0; + eval { + my $query = 'DESCRIBE ' . $table; + my $sth = $dbh->prepare($query); + $sth->execute(); + $sth->finish; + $query = 'SHOW COLUMNS FROM ' . $table; + $sth = $dbh->prepare($query); + $sth->execute(); + my $fields = {}; + while (my $hashRef = $sth->fetchrow_hashref) { + $fields->{$hashRef->{Field}} = $hashRef->{Field}; + } + my @fields; + my $fieldsR; + if ($fieldsA) { + $fieldsR = $fieldsA; + } else { + $fieldsR = \@fields; + _getFields($nodeFields, $fieldsR, $format); + } + $ret = 1; + for (@$fieldsR) { + unless (exists($fields->{$_})) { + $ret = 0; + last; + } + } + }; + return $ret; +}#_check_validity_worksheet + + +# Import the data from an excel-xml/ods to mysql tables. +sub _import_table +{ + my ($dbh, $table, $frameworkcode, $dom, $PKArray, $format) = @_; + my %fields2Delete; + my $query; + eval { + my @fields = @$PKArray; + shift @fields; + $query = 'SELECT ' . join(',', @fields) . ' FROM ' . $table . ' WHERE frameworkcode=?'; + my $sth = $dbh->prepare($query); + $sth->execute($frameworkcode); + my $field; + while (my $hashRef = $sth->fetchrow_hashref) { + $field = ''; + map { $field .= $hashRef->{$_} . '_'; } @fields; + chop $field; + $fields2Delete{$field} = 1; + } + $sth->finish; + }; + my $ok = 0; + if ($format && $format eq 'ods') { + $ok = _import_table_ods($dbh, $table, $frameworkcode, $dom, $PKArray, \%fields2Delete); + } else { + $ok = _import_table_excel($dbh, $table, $frameworkcode, $dom, $PKArray, \%fields2Delete); + } + if ($ok) { + if (($ok = scalar(keys %fields2Delete)) > 0) { + $query = 'DELETE FROM ' . $table . ' WHERE '; + map {$query .= $_ . '=? AND ';} @$PKArray; + $query = substr($query, 0, -4); + my $sth = $dbh->prepare($query); + for (keys %fields2Delete) { + eval { + $sth->execute(($frameworkcode, split('_', $_))); + }; + } + } + } else { + $ok = -1; + } + return $ok; +}#_import_table + + +# Process the rows of a worksheet and insert/update them in a mysql table. +sub _processRows_Table +{ + my ($dbh, $frameworkcode, $nodeR, $table, $PKArray, $format, $fields2Delete) = @_; + + my $query; + my @fields = (); + my $fields = ''; + my $dataStr = ''; + my $updateStr = ''; + my $j = 0; + my $db_scheme = C4::Context->config("db_scheme"); + my $ok = 0; + my @fieldsPK = @$PKArray; + shift @fieldsPK; + while ($nodeR) { + if ($nodeR->nodeType == 1 && (($format && $format eq 'ods' && $nodeR->nodeName =~ /(?:table:)?table-row/) || ($nodeR->nodeName =~ /(?:ss:)?Row/)) && $nodeR->hasChildNodes()) { + if ($j == 0) { + # Get name columns + _getFields($nodeR, \@fields, $format); + return 0 unless _check_validity_worksheet($dbh, $table, $nodeR, \@fields, $format); + $fields = join(',', @fields); + $dataStr = ''; + map { $dataStr .= '?,';} @fields; + chop($dataStr) if ($dataStr); + $updateStr = ''; + map { $updateStr .= $_ . '=?,';} @fields; + chop($updateStr) if ($updateStr); + } else { + # Get data from row + my ($dataFields, $dataFieldsR) = _getDataFields($frameworkcode, $nodeR, \@fields, $format); + if (scalar(@fields) == scalar(@$dataFieldsR)) { + if ($db_scheme eq 'mysql') { + $query = 'INSERT INTO ' . $table . ' (' . $fields . ') VALUES (' . $dataStr . ') ON DUPLICATE KEY UPDATE ' . $updateStr; + } else { + $query = 'INSERT INTO ' . $table . ' (' . $fields . ') VALUES (' . $dataStr . ')'; + } + eval { + my $sth = $dbh->prepare($query); + if ($db_scheme eq 'mysql') { + $sth->execute((@$dataFieldsR, @$dataFieldsR)); + } else { + $sth->execute(@$dataFieldsR); + } + }; + if ($@) { + unless ($db_scheme eq 'mysql') { + $query = 'UPDATE ' . $table . ' SET ' . $updateStr . ' WHERE '; + map {$query .= $_ . '=? AND ';} @$PKArray; + $query = substr($query, 0, -4); + eval { + my $sth2 = $dbh->prepare($query); + my @dataPK = (); + map {push @dataPK, $dataFields->{$_};} @$PKArray; + $sth2->execute((@$dataFieldsR, @dataPK)); + }; + $ok = 1 unless ($@); + } + $debug and warn "Error _processRows_Table $@\n"; + } else { + $ok = 1; + } + if ($ok) { + my $field = ''; + map { $field .= $dataFields->{$_} . '_'; } @fieldsPK; + chop $field; + delete $fields2Delete->{$field} if (exists($fields2Delete->{$field})); + } + $ok = 0; + } + } + $j++; + } + $nodeR = $nodeR->nextSibling; + } + return 1; +}#_processRows_Table + + +# Import worksheet from the ods content.xml file to the mysql table +sub _import_table_ods +{ + my ($dbh, $table, $frameworkcode, $dom, $PKArray, $fields2Delete) = @_; + + my $xc = XML::LibXML::XPathContext->new($dom); + $xc->registerNs('xmlns:office','urn:oasis:names:tc:opendocument:xmlns:office:1.0'); + $xc->registerNs('xmlns:table','urn:oasis:names:tc:opendocument:xmlns:table:1.0'); + $xc->registerNs('xmlns:text','urn:oasis:names:tc:opendocument:xmlns:text:1.0'); + my @nodes; + @nodes = $xc->findnodes('//table:table[@table:name="' . $table . '"]'); + if (@nodes == 1 && $nodes[0]->hasChildNodes()) { + my $nodeR = $nodes[0]->firstChild; + return _processRows_Table($dbh, $frameworkcode, $nodeR, $table, $PKArray, 'ods', $fields2Delete); + } else { + $debug and warn "Error _import_table_ods there's not worksheet for $table\n"; + } + return 0; +}#_import_table_ods + + +# Import worksheet from the excel-xml file to the mysql table +sub _import_table_excel +{ + my ($dbh, $table, $frameworkcode, $dom, $PKArray, $fields2Delete) = @_; + + my $xc = XML::LibXML::XPathContext->new($dom); + $xc->registerNs('xmlns','urn:schemas-microsoft-com:office:spreadsheet'); + $xc->registerNs('xmlns:ss','urn:schemas-microsoft-com:office:spreadsheet'); + $xc->registerNs('xmlns:x','urn:schemas-microsoft-com:office:excel'); + my @nodes; + @nodes = $xc->findnodes('//ss:Worksheet[@ss:Name="' . $table . '"]'); + if (@nodes > 0) { + for (my $i=0; $i < @nodes; $i++) { + my @nodesT = $nodes[$i]->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Table'); + if (@nodesT == 1 && $nodesT[0]->hasChildNodes()) { + my $nodeR = $nodesT[0]->firstChild; + return _processRows_Table($dbh, $frameworkcode, $nodeR, $table, $PKArray, undef, $fields2Delete); + } + } + } else { + $debug and warn "Error _import_table_excel there's not worksheet for $table\n"; + } + return 0; +}#_import_table_excel + + +# Get the data from a cell on a ods file through the value attribute or the text node +sub _getDataNodeODS +{ + my $node = shift; + + my $data; + my $repeated = 0; + if ($node->nodeType == 1 && $node->nodeName =~ /(?:table:)?table-cell/) { + if ($node->hasAttributeNS('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'value')) { + $data = $node->getAttributeNS('urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'value'); + } elsif ($node->hasChildNodes()) { + my @nodes2 = $node->getElementsByTagNameNS('urn:oasis:names:tc:opendocument:xmlns:text:1.0', 'p'); + if (@nodes2 == 1 && $nodes2[0]->hasChildNodes()) { + $data = $nodes2[0]->firstChild->nodeValue; + } + } + if ($node->hasAttributeNS('urn:oasis:names:tc:opendocument:xmlns:table:1.0', 'number-columns-repeated')) { + $repeated = $node->getAttributeNS('urn:oasis:names:tc:opendocument:xmlns:table:1.0', 'number-columns-repeated'); + } + } + return ($data, $repeated); +}#_getDataNodeODS + + +# Get the data from a row of a spreadsheet +sub _getDataFields +{ + my ($frameworkcode, $node, $fields, $format) = @_; + + my $dataFields = {}; + my @dataFieldsA = (); + if ($node && $node->hasChildNodes()) { + my $node2 = $node->firstChild; + my ($data, $repeated); + my $i = 0; + my $ok = 0; + $repeated = 0; + while ($node2) { + if ($format && $format eq 'ods') { + ($data, $repeated) = _getDataNodeODS($node2) if ($repeated <= 0); + $repeated--; + $ok = 1 if (defined($data)); + } else { + if ($node2->nodeType == 1 && $node2->nodeName =~ /(?:ss:)?Cell/) { + my @nodes3 = $node2->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Data'); + if (@nodes3 == 1 && $nodes3[0]->hasChildNodes()) { + $data = $nodes3[0]->firstChild->nodeValue; + $ok = 1; + } + } + } + if ($ok) { + $data = '' if ($data eq '#'); + $data = $frameworkcode if ($fields->[$i] eq 'frameworkcode'); + $dataFields->{$fields->[$i]} = $data; + push @dataFieldsA, $data; + $i++; + } + $ok = 0; + $node2 = $node2->nextSibling if ($repeated <= 0); + } + } + return ($dataFields, \@dataFieldsA); +}#_getDataFields + + +# Get the data from the first row to know the column names +sub _getFields +{ + my ($node, $fields, $format) = @_; + + if ($node && $node->hasChildNodes()) { + my $node2 = $node->firstChild; + my ($data, $repeated); + while ($node2) { + if ($format && $format eq 'ods') { + ($data, $repeated) = _getDataNodeODS($node2); + push @$fields, $data if (defined($data)); + } else { + if ($node2->nodeType == 1 && $node2->nodeName =~ /(?:ss:)?Cell/) { + my @nodes3 = $node2->getElementsByTagNameNS('urn:schemas-microsoft-com:office:spreadsheet', 'Data'); + if (@nodes3 == 1 && $nodes3[0]->hasChildNodes()) { + $data = $nodes3[0]->firstChild->nodeValue; + push @$fields, $data; + } + } + } + $node2 = $node2->nextSibling; + } + } +}#_getFields + + + + +1; +__END__ + +=head1 AUTHOR + +Koha Development Team <http://koha-community.org/> + +=cut + + diff --git a/admin/import_export_framework.pl b/admin/import_export_framework.pl new file mode 100755 index 0000000..756b1a6 --- /dev/null +++ b/admin/import_export_framework.pl @@ -0,0 +1,68 @@ +#!/usr/bin/perl + +# Copyright 2010-2011 MASmedios.com y Ministerio de Cultura +# +# 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 C4::Context; +use C4::ImportExportFramework; + +my $input = new CGI; + +my $frameworkcode = $input->param('frameworkcode') || ''; +my $action = $input->param('action') || 'export'; + +## Exporting +if ($action eq 'export' && $input->request_method() eq 'GET') { + my $strXml = ''; + ExportFramework($frameworkcode, \$strXml, $input->param('type_export_' . $frameworkcode)); + if ($input->param('type_export_' . $frameworkcode) eq 'excel') { + # Excel-xml file + print $input->header(-type => 'application/excel', -attachment => 'export_' . $frameworkcode . '.xml'); + print $strXml; + } else { + # ODS file + my $strODS = ''; + createODS($strXml, 'en', \$strODS); + print $input->header(-type => 'application/vnd.oasis.opendocument.spreadsheet', -attachment => 'export_' . $frameworkcode . '.ods'); + print $strODS; + } +## Importing +} elsif ($input->request_method() eq 'POST') { + my $ok = -1; + my $fieldname = 'file_import_' . $frameworkcode; + my $filename = $input->param($fieldname); + # upload the input file + if ($filename && $filename =~ /\.(ods|xml)$/i) { + my $extension = $1; + my $uploadFd = $input->upload($fieldname); + if ($uploadFd && !$input->cgi_error) { + my $tmpfilename = $input->tmpFileName($input->param($fieldname)); + $filename = $tmpfilename . '.' . $extension; # rename the tmp file with the extension + $ok = ImportFramework($filename, $frameworkcode, 1) if (rename($tmpfilename, $filename)); + } + } + if ($ok >= 0) { # If everything went ok go to the framework marc structure + print $input->redirect( -location => '/cgi-bin/koha/admin/marctagstructure.pl?frameworkcode=' . $frameworkcode); + } else { + # If something failed go to the list of frameworks and show message + print $input->redirect( -location => '/cgi-bin/koha/admin/biblio_framework.pl?error_import_export=' . $frameworkcode); + } +} diff --git a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css old mode 100644 new mode 100755 index 66b092c..dd3700a --- a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css +++ b/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css @@ -1924,3 +1924,51 @@ ul.budget_hierarchy li:first-child:after { margin : 1em 0; } fieldset.rows+h3 {clear:both;padding-top:.5em;} + +.import_export{ + position:relative; +} +.import_export .import_export_options{ + background: white; + border: 1px solid #CDCDCD; + left: 60px; + padding: 10px; + position: absolute; + top: 0; + z-index: 1; + width: 300px; +} +.import_export_options li{ + display: block; + list-style: none; + padding-top: 10px; +} +.import_export_options .import_export_close { + cursor: pointer; + text-decoration: underline; +} +.import_export_options .export_ok { + padding: 10; + background: #E3E3E3 none; + cursor: pointer; + margin-left: 20px; + border: none; +} +.import_export_options .import_ok { + padding: 10; + background: #E3E3E3 none; + cursor: pointer; + margin-left: 20px; + border: none; +} +.form_import .input_import { + border: 1px solid #bcbcbc; +} +.import_export_options .importing { + padding: inherit; + background: none; +} +.li_close_import_export { + text-align: right; +} + diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl old mode 100644 new mode 100755 index ba5dde8..87cc082 --- a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/admin/biblio_framework.tmpl @@ -48,6 +48,88 @@ $(document).ready(function() { }); //]]> </script> +<script type="text/javascript"> +/* Import/Export from/to spreadsheet */ + + var importing = false; + + $(document).ready(function() { + $("body").css("cursor", "auto"); + $('.import_export_options').hide(); + $('a.import_export_fw').click(function() { + if (!importing) { + $('.import_export_options').hide(); + $(this).next().show('slide'); + } + return false; + }); + $('.import_export_close').click(function() { + if (!importing) $('.import_export_options').fadeOut('fast'); + }); + $('.input_import').val(""); + + var matches = new RegExp("\\?error_import_export=(.+)$").exec(window.location.search); + if (matches && matches.length > 1) { + alert("Error importing the framework " + decodeURIComponent(matches[1])); + } + }); + + $(function() { + $('input.input_import').change( function() { + var filename = $(this).val(); + if ( ! /(?:\.ods|\.xml)$/.test(filename)) { + $(this).css("background-color","yellow"); + try { + var pos = filename.lastIndexOf("/"); + if (pos < 0) pos = filename.lastIndexOf("\\"); + if (pos < 0) pos = filename.length; + var id = $(this).attr('id'); + var obj = document.getElementById(id); + if (obj.setSelectionRange) { + obj.focus(); + obj.setSelectionRange(pos * 2, filename.length * 2); + } else if (obj.createTextRange) { + var range = obj.createTextRange(); + range.collapse(true); + range.moveEnd('character', filename.length * 2); + range.moveStart('character', pos); + range.select(); + } + } catch (e) {} + alert('Please select an ods or xml file'); + $(this).val(""); + $(this).css("background-color","white"); + } + }); + $('form.form_export').submit(function() { + $('.import_export_options').hide(); + return true; + }); + $('form.form_import').submit(function() { + var id = $(this).attr('id'); + var obj = $('#' + id + ' input:file'); + if (/(?:\.ods|\.xml)$/.test(obj.val())) { + if (confirm('Do you really want to import the framework fields/subfields (will overwrite current configuration, for safety reasons please make before an export to have a backup file)?')) { + var frameworkcode = $('#' + id + ' input:hidden[name=frameworkcode]').val(); + $('#importing_' + frameworkcode).css('display', 'block'); + if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) $("body").css("cursor", "progress"); + importing = true; + return true; + } else + return false; + } + obj.css("background-color","yellow"); + alert('Please select an ods or xml file'); + obj.val(""); + obj.css("background-color","white"); + return false; + }); + }); + + + +</script> + </head> <body> <!-- TMPL_INCLUDE NAME="header.inc" --> @@ -115,6 +197,8 @@ $(document).ready(function() { <th> </th> <th>Edit</th> <th>Delete</th> + <th title="Export framework structure (fields, subfields) to a spreadsheet file (.xml, .ods)">Export</th> + <th title="Import framework structure (fields, subfields) from a spreadsheet file (.xml, .ods)">Import</th> </tr> <tr> <td> </td> @@ -122,6 +206,34 @@ $(document).ready(function() { <td><a href="marctagstructure.pl?frameworkcode=<!-- TMPL_VAR NAME="frameworkcode" -->">MARC structure</a></td> <td> </td> <td> </td> + <td><div class="import_export"><a class="import_export_fw" href="#" title="Export <!-- TMPL_VAR NAME="frameworkcode" --> framework structure (fields, subfields) to a spreadsheet file (.xml, .ods)">Export</a> + <div class="import_export_options"> + <form action="import_export_framework.pl" name="form_<!-- TMPL_VAR NAME="frameworkcode" -->" method="get" target="_blank" class="form_export"> + <input type="hidden" name="frameworkcode" value="<!-- TMPL_VAR NAME="frameworkcode" -->" /> + <ul> + <li class="li_close_import_export"><span class="import_export_close" title="Close popup">Close</span></li> + <li><input type="radio" name="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" value="excel" id="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" checked="checked" /><label for="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" title="Export to Excel as xml format, compatible with OpenOffice/LibreOffice as well">Export to Excel with xml format</label></li> + <li><input type="radio" name="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" value="ods" id="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" /><label for="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->">Export to OpenDocument Spreadsheet format</label></li> + <li><input type="submit" class="export_ok" href="#" value="Export" title="Export to a spreadsheet" /></li> + </ul> + </form> + </div> + </div> + </td> + <td><div class="import_export"><a href="#" class="import_export_fw" title="Import <!-- TMPL_VAR NAME="frameworkcode" --> framework structure (fields, subfields) from a spreadsheet file (.xml, .ods)">Import</a> + <div class="import_export_options"> + <form action="/cgi-bin/koha/admin/import_export_framework.pl" name="form_i_<!-- TMPL_VAR NAME="frameworkcode" -->" id="form_i_<!-- TMPL_VAR NAME="frameworkcode" -->" method="post" enctype="multipart/form-data" class="form_import"> + <input type="hidden" name="frameworkcode" value="<!-- TMPL_VAR NAME="frameworkcode" -->" /> + <input type="hidden" name="action" value="import" /> + <ul> + <li class="li_close_import_export"><span class="import_export_close" title="Close popup">Close</span></li> + <li><label for="file_import_<!-- TMPL_VAR NAME="frameworkcode" -->" title="Import from a spreadsheet, formats available: ods, xml (formatted from excel)">Spreadsheet file</label><input type="file" name="file_import_<!-- TMPL_VAR NAME="frameworkcode" -->" id="file_import_<!-- TMPL_VAR NAME="frameworkcode" -->" class="input_import" value="" autocomplete="off" /></li> + <li><input type="submit" class="import_ok" value="Import" title="Import from a spreadsheet" /><div id="importing_<!-- TMPL_VAR NAME="frameworkcode" -->" style="display:none" class="importing"><img src="/intranet-tmpl/prog/img/loading.gif" />Importing...</div></li> + </ul> + </form> + </div> + </div> + </td> </tr> <!-- note highlight assignment appears backwards because we already have a normal row for Default --> <!-- TMPL_LOOP NAME="loop" --> @@ -133,6 +245,35 @@ $(document).ready(function() { <td><a href="marctagstructure.pl?frameworkcode=<!-- TMPL_VAR name="frameworkcode" -->" >MARC structure</a></td> <td><a href="<!-- TMPL_VAR name="script_name" -->?op=add_form&frameworkcode=<!-- TMPL_VAR name="frameworkcode" escape="HTML" -->">Edit</a></td> <td><a href="<!-- TMPL_VAR name="script_name" -->?op=delete_confirm&frameworkcode=<!-- TMPL_VAR name="frameworkcode" escape="HTML" -->">Delete</a></td> + <td> + <div class="import_export"><a class="import_export_fw" href="#" title="Export <!-- TMPL_VAR NAME="frameworkcode" --> framework structure (fields, subfields) to a spreadsheet file (.xml, .ods)">Export</a> + <div class="import_export_options"> + <form action="import_export_framework.pl" name="form_<!-- TMPL_VAR NAME="frameworkcode" -->" method="get" target="_blank" class="form_export"> + <input type="hidden" name="frameworkcode" value="<!-- TMPL_VAR NAME="frameworkcode" -->" /> + <ul> + <li class="li_close_import_export"><span class="import_export_close" title="Close popup">Close</span></li> + <li><input type="radio" name="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" value="excel" id="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" checked="checked" /><label for="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" title="Export to Excel as xml format, compatible with OpenOffice/LibreOffice as well">Export to Excel as xml format</label></li> + <li><input type="radio" name="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" value="ods" id="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->" /><label for="type_export_<!-- TMPL_VAR NAME="frameworkcode" -->">Export to OpenDocument Spreadsheet format</label></li> + <li><input type="submit" class="export_ok" href="#" value="Export" title="Export to a spreadsheet" /></li> + </ul> + </form> + </div> + </div> + </td> + <td><div class="import_export"><a class="import_export_fw" href="#" title="Import <!-- TMPL_VAR NAME="frameworkcode" --> framework structure (fields, subfields) from a spreadsheet file (.xml, .ods)">Import</a> + <div class="import_export_options"> + <form action="/cgi-bin/koha/admin/import_export_framework.pl" name="form_i_<!-- TMPL_VAR NAME="frameworkcode" -->" id="form_i_<!-- TMPL_VAR NAME="frameworkcode" -->" method="post" enctype="multipart/form-data" class="form_import"> + <input type="hidden" name="frameworkcode" value="<!-- TMPL_VAR NAME="frameworkcode" -->" /> + <input type="hidden" name="action" value="import" /> + <ul> + <li class="li_close_import_export"><span class="import_export_close" title="Close popup">Close</span></li> + <li><label for="file_import_<!-- TMPL_VAR NAME="frameworkcode" -->" title="Import from a spreadsheet, formats available: ods, xml (formatted from excel)">Spreadsheet file</label><input type="file" name="file_import_<!-- TMPL_VAR NAME="frameworkcode" -->" id="file_import_<!-- TMPL_VAR NAME="frameworkcode" -->" class="input_import" value="" autocomplete="off" /></li> + <li><input type="submit" class="import_ok" value="Import" title="Import from a spreadsheet" /><div id="importing_<!-- TMPL_VAR NAME="frameworkcode" -->" style="display:none" class="importing"><img src="/intranet-tmpl/prog/img/loading.gif" />Importing...</div></li> + </ul> + </form> + </div> + </div> + </td> </tr> <!-- /TMPL_LOOP --> </table> -- 1.5.6.5