summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Cecchetti <marco.cecchetti@collabora.com>2021-01-17 23:36:53 +0100
committerAndras Timar <andras.timar@collabora.com>2021-01-19 15:16:08 +0100
commit10db92590353caeb515dd650a32eb09f352eea98 (patch)
tree8f7699d448ba4d6828225cda89c6234e7ec8600b
parent8d29f3ab72ec91ab7fad55379a14afd41112532a (diff)
filter: svg: js engine: improving text fields handling
Added support for slide number and current date, current time fields inserted by the user on slides or master pages. Change-Id: If21b06c58e8fdcc240a540ee6fa87f48a6eb86af Reviewed-on: https://gerrit.libreoffice.org/c/core/+/109496 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Ashod Nakashian <ash@collabora.com>
-rw-r--r--filter/source/svg/presentation_engine.js158
-rw-r--r--filter/source/svg/svgwriter.cxx35
-rw-r--r--filter/source/svg/svgwriter.hxx1
3 files changed, 164 insertions, 30 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 4dd876defba9..d0d0a0b60db7 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -4458,6 +4458,8 @@ var aSlideNumberClassName = 'Slide_Number';
var aDateTimeClassName = 'Date/Time';
var aFooterClassName = 'Footer';
var aHeaderClassName = 'Header';
+var aDateClassName = 'Date';
+var aTimeClassName = 'Time';
// Creating a namespace dictionary.
var NSS = {};
@@ -4895,6 +4897,8 @@ function MetaDocument()
this.aTextFieldHandlerSet = {};
this.aTextFieldContentProviderSet = [];
this.aSlideNumberProvider = new SlideNumberProvider( this.nStartSlideNumber + 1, this.sPageNumberingType );
+ this.aCurrentDateProvider = new CurrentDateTimeProvider( null, '<date>' );
+ this.aCurrentTimeProvider = new CurrentDateTimeProvider( null, '<time>' );
// We create a map with key an id and value the svg element containing
// the animations performed on the slide with such an id.
@@ -5050,6 +5054,9 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
this.backgroundId = this.backgroundElement.getAttribute( 'id' );
}
+ // We initialize text fields
+ this.initPlaceholderElements();
+
// We initialize the MasterPage object that provides direct access to
// the target master page element.
this.masterPage = this.initMasterPage();
@@ -5076,6 +5083,8 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
this.aTextFieldContentProviderSet[aDateTimeClassName] = this.initDateTimeFieldContentProvider( aOOOAttrDateTimeField );
this.aTextFieldContentProviderSet[aFooterClassName] = this.initFixedTextFieldContentProvider( aOOOAttrFooterField );
this.aTextFieldContentProviderSet[aHeaderClassName] = this.initFixedTextFieldContentProvider( aOOOAttrHeaderField );
+ this.aTextFieldContentProviderSet[aDateClassName] = this.theMetaDoc.aCurrentDateProvider;
+ this.aTextFieldContentProviderSet[aTimeClassName] = this.theMetaDoc.aCurrentTimeProvider;
// We init the slide duration when automatic slide transition is enabled
this.fDuration = this.initSlideDuration();
@@ -5146,6 +5155,23 @@ updateMasterPageView : function()
},
/*** private methods ***/
+
+// It handles a text field inserted on a slide, not on a master page.
+initPlaceholderElements : function()
+{
+ var aPlaceholderList = getElementsByClassName(this.pageElement , 'PlaceholderText' );
+ var i = 0;
+ for( ; i < aPlaceholderList.length; ++i )
+ {
+ var aPlaceholderElem = aPlaceholderList[i];
+ var sContent = aPlaceholderElem.textContent;
+ if( sContent === '<date>' )
+ aPlaceholderElem.textContent = new Date().toLocaleDateString();
+ else if( sContent === '<time>' )
+ aPlaceholderElem.textContent = new Date().toLocaleTimeString();
+ }
+},
+
initMasterPage : function()
{
var sMasterPageId = this.element.getAttributeNS( NSS['ooo'], aOOOAttrMaster );
@@ -5322,6 +5348,34 @@ getSlideAnimationsRoot : function()
}; // end MetaSlide prototype
+function getTextFieldType ( elem )
+{
+ var sFieldType = null;
+ var sClass = elem.getAttribute('class');
+ if( sClass.endsWith( 'TextShape' ) )
+ {
+ var aPlaceholderElement = getElementByClassName( elem, 'PlaceholderText' );
+ if (aPlaceholderElement)
+ {
+ var sContent = aPlaceholderElement.textContent
+ if (sContent === '<number>')
+ sFieldType = aSlideNumberClassName;
+ else if (sContent === '<date>')
+ sFieldType = aDateClassName;
+ else if (sContent === '<time>')
+ sFieldType = aTimeClassName;
+ }
+ }
+ return sFieldType;
+}
+
+function isTextFieldByClassName ( sClassName )
+{
+ return sClassName === aDateTimeClassName || sClassName === aFooterClassName
+ || sClassName === aHeaderClassName || sClassName.startsWith( aSlideNumberClassName )
+ || sClassName.startsWith( aDateClassName ) || sClassName.startsWith( aTimeClassName );
+}
+
/** Class MasterPage
* This class gives direct access to a master page element and to the following
* elements included in the master page:
@@ -5384,6 +5438,7 @@ function MasterPage( sMasterPageId, aMetaSlide )
// The background objects group element that contains every element presents
// on the master page except the background element.
this.backgroundObjects = getElementByClassName( this.element, 'BackgroundObjects' );
+ this.aBackgroundObjectSubGroupIdList = [];
if( this.backgroundObjects )
{
this.backgroundObjectsId = this.backgroundObjects.getAttribute( 'id' );
@@ -5397,13 +5452,26 @@ function MasterPage( sMasterPageId, aMetaSlide )
var nSubGroupId = 1;
var sClass;
var sId = '';
- this.aBackgroundObjectSubGroupIdList = [];
var i = 0;
for( ; i < aBackgroundObjectList.length; ++i )
{
- sClass = aBackgroundObjectList[i].getAttribute( 'class' );
- if( !sClass || ( ( sClass !== aDateTimeClassName ) && ( sClass !== aFooterClassName )
- && ( sClass !== aHeaderClassName ) && ( sClass !== aSlideNumberClassName ) ) )
+ var aObject = aBackgroundObjectList[i];
+ sClass = null;
+ var sFieldType = getTextFieldType( aObject );
+ if( sFieldType && aObject.firstElementChild )
+ {
+ var sObjId = aObject.firstElementChild.getAttribute( 'id' );
+ if( sObjId )
+ {
+ sClass = sFieldType + '.' + sObjId;
+ aObject.setAttribute('class', sClass);
+ }
+ }
+ if( !sClass )
+ {
+ sClass = aBackgroundObjectList[i].getAttribute('class');
+ }
+ if( !sClass || !isTextFieldByClassName( sClass ) )
{
if( nCount === 0 )
{
@@ -5447,10 +5515,14 @@ MasterPage.prototype =
initPlaceholderShapes : function()
{
- this.aPlaceholderShapeSet[ aSlideNumberClassName ] = new PlaceholderShape( this, aSlideNumberClassName );
- this.aPlaceholderShapeSet[ aDateTimeClassName ] = new PlaceholderShape( this, aDateTimeClassName );
- this.aPlaceholderShapeSet[ aFooterClassName ] = new PlaceholderShape( this, aFooterClassName );
- this.aPlaceholderShapeSet[ aHeaderClassName ] = new PlaceholderShape( this, aHeaderClassName );
+ var sClassName;
+ var i = 0;
+ for( ; i < this.aBackgroundObjectSubGroupIdList.length; ++i )
+ {
+ sClassName = this.aBackgroundObjectSubGroupIdList[i];
+ if( isTextFieldByClassName( sClassName ) )
+ this.aPlaceholderShapeSet[ sClassName ] = new PlaceholderShape( this, sClassName );
+ }
}
}; // end MasterPage prototype
@@ -5694,22 +5766,25 @@ MasterPageView.prototype.createElement = function()
for( ; i < aBackgroundObjectSubGroupIdList.length; ++i )
{
sId = aBackgroundObjectSubGroupIdList[i];
- if( sId === aSlideNumberClassName )
+ if( sId.startsWith( aSlideNumberClassName ) )
{
// Slide Number Field
// The cloned element is appended directly to the field group element
// since there is no slide number field content shared between two slide
// (because the slide number of two slide is always different).
- if( aPlaceholderShapeSet[aSlideNumberClassName] &&
- aPlaceholderShapeSet[aSlideNumberClassName].isValid() &&
- this.aMetaSlide.nIsPageNumberVisible &&
+ var nIsPageNumberVisible = sId === aSlideNumberClassName ? this.aMetaSlide.nIsPageNumberVisible : true;
+ if( aPlaceholderShapeSet[sId] &&
+ aPlaceholderShapeSet[sId].isValid() &&
+ nIsPageNumberVisible &&
aTextFieldContentProviderSet[aSlideNumberClassName] )
{
- this.aSlideNumberFieldHandler =
- new SlideNumberFieldHandler( aPlaceholderShapeSet[aSlideNumberClassName],
- aTextFieldContentProviderSet[aSlideNumberClassName] );
- this.aSlideNumberFieldHandler.update( this.aMetaSlide.nSlideNumber );
- this.aSlideNumberFieldHandler.appendTo( this.aBackgroundObjectsElement );
+ var aSlideNumberFieldHandler =
+ new SlideNumberFieldHandler( aPlaceholderShapeSet[sId],
+ aTextFieldContentProviderSet[aSlideNumberClassName] );
+ aSlideNumberFieldHandler.update( this.aMetaSlide.nSlideNumber );
+ aSlideNumberFieldHandler.appendTo( this.aBackgroundObjectsElement );
+ if ( sId === aSlideNumberClassName )
+ this.aSlideNumberFieldHandler = aSlideNumberFieldHandler;
}
}
else if( sId === aDateTimeClassName )
@@ -5745,6 +5820,18 @@ MasterPageView.prototype.createElement = function()
aTextFieldHandlerSet, sMasterSlideId );
}
}
+ else if( sId.startsWith( aDateClassName ) )
+ {
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+ aTextFieldContentProviderSet, aDefsElement,
+ aTextFieldHandlerSet, sMasterSlideId );
+ }
+ else if( sId.startsWith( aTimeClassName ) )
+ {
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+ aTextFieldContentProviderSet, aDefsElement,
+ aTextFieldHandlerSet, sMasterSlideId );
+ }
else
{
// init BackgroundObjectSubGroup elements
@@ -5766,23 +5853,25 @@ MasterPageView.prototype.createElement = function()
};
MasterPageView.prototype.initTextFieldHandler =
- function( sClassName, aPlaceholderShapeSet, aTextFieldContentProviderSet,
+ function( sId, aPlaceholderShapeSet, aTextFieldContentProviderSet,
aDefsElement, aTextFieldHandlerSet, sMasterSlideId )
{
var sRefId = null;
var aTextFieldHandler = null;
- var aPlaceholderShape = aPlaceholderShapeSet[sClassName];
+ var sClassName = sId.split('.')[0];
+ var aPlaceholderShape = aPlaceholderShapeSet[sId];
+ var aTextFieldContentProvider = aTextFieldContentProviderSet[sClassName];
if( aPlaceholderShape && aPlaceholderShape.isValid()
- && aTextFieldContentProviderSet[sClassName] )
+ && aTextFieldContentProvider )
{
- var sTextFieldContentProviderId = aTextFieldContentProviderSet[sClassName].sId;
+ var sTextFieldContentProviderId = aTextFieldContentProvider.sId;
// We create only one single TextFieldHandler object (and so one only
// text field clone) per master slide and text content.
if ( !aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] )
{
aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] =
new TextFieldHandler( aPlaceholderShape,
- aTextFieldContentProviderSet[sClassName] );
+ aTextFieldContentProvider );
aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
aTextFieldHandler.update();
aTextFieldHandler.appendTo( aDefsElement );
@@ -5794,7 +5883,7 @@ MasterPageView.prototype.initTextFieldHandler =
sRefId = aTextFieldHandler.sId;
}
else if( aPlaceholderShape && aPlaceholderShape.element && aPlaceholderShape.element.firstElementChild
- && !aPlaceholderShape.textElement && !aTextFieldContentProviderSet[sClassName] )
+ && !aPlaceholderShape.textElement && !aTextFieldContentProvider )
{
sRefId = aPlaceholderShape.element.firstElementChild.getAttribute('id');
}
@@ -6013,10 +6102,16 @@ FixedTextProvider.prototype.update = function( aFixedTextField )
* The svg element that contains the date/time format for one or more
* master slide date/time field.
*/
-function CurrentDateTimeProvider( aTextFieldContentElement )
+function CurrentDateTimeProvider( aTextFieldContentElement, sDateTimeFormat )
{
CurrentDateTimeProvider.superclass.constructor.call( this, aTextFieldContentElement );
- this.dateTimeFormat = getOOOAttribute( aTextFieldContentElement, aOOOAttrDateTimeFormat );
+ if( aTextFieldContentElement )
+ this.dateTimeFormat = getOOOAttribute( aTextFieldContentElement, aOOOAttrDateTimeFormat );
+ else
+ {
+ this.dateTimeFormat = sDateTimeFormat;
+ this.sId = 'DateTimeProvider.' + sDateTimeFormat;
+ }
}
extend( CurrentDateTimeProvider, TextFieldContentProvider );
@@ -6031,17 +6126,22 @@ extend( CurrentDateTimeProvider, TextFieldContentProvider );
*/
CurrentDateTimeProvider.prototype.update = function( aDateTimeField )
{
- var sText = this.createDateTimeText( this.dateTimeFormat );
+ var sText = this.createDateTimeText();
aDateTimeField.setTextContent( sText );
};
/*** private methods ***/
-CurrentDateTimeProvider.prototype.createDateTimeText = function( /*sDateTimeFormat*/ )
+CurrentDateTimeProvider.prototype.createDateTimeText = function()
{
// TODO handle date/time format
- var aDate = new Date();
- var sDate = aDate.toLocaleString();
+ var sDate;
+ if( this.dateTimeFormat === '<date>' )
+ sDate = new Date().toLocaleDateString();
+ else if( this.dateTimeFormat === '<time>' )
+ sDate = new Date().toLocaleTimeString();
+ else
+ sDate = new Date().toLocaleDateString();
return sDate;
};
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index e4a7c4bac7a7..2e4c00b7fbf8 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -1091,9 +1091,9 @@ bool SVGTextWriter::nextTextPortion()
{
mrCurrentTextPortion.clear();
mbIsURLField = false;
- mbIsPlaceholderShape = false;
if( mrTextPortionEnumeration.is() && mrTextPortionEnumeration->hasMoreElements() )
{
+ mbIsPlaceholderShape = false;
#if OSL_DEBUG_LEVEL > 0
OUString sInfo;
#endif
@@ -1111,6 +1111,7 @@ bool SVGTextWriter::nextTextPortion()
}
#endif
msPageCount = "";
+ msDateTimeType = "";
if( xPortionTextRange.is() )
{
#if OSL_DEBUG_LEVEL > 0
@@ -1157,6 +1158,31 @@ bool SVGTextWriter::nextTextPortion()
#if OSL_DEBUG_LEVEL > 0
sInfo += "text field type: " + sFieldName + "; content: " + xTextField->getPresentation( /* show command: */ false ) + "; ";
#endif
+ // This case handle Date or Time text field inserted by the user
+ // on both page/master page. It doesn't handle the standard Date/Time field.
+ if( sFieldName == "DateTime" )
+ {
+ Reference<XPropertySet> xTextFieldPropSet(xTextField, UNO_QUERY);
+ if( xTextFieldPropSet.is() )
+ {
+ Reference<XPropertySetInfo> xPropSetInfo = xTextFieldPropSet->getPropertySetInfo();
+ if( xPropSetInfo.is() )
+ {
+ // The standard Date/Time field has no property.
+ // Trying to get a property value on such field would cause a runtime exception.
+ // So the hasPropertyByName check is needed.
+ bool bIsFixed = true;
+ if( xPropSetInfo->hasPropertyByName("IsFixed") && ( ( xTextFieldPropSet->getPropertyValue( "IsFixed" ) ) >>= bIsFixed ) && !bIsFixed )
+ {
+ bool bIsDate;
+ if( xPropSetInfo->hasPropertyByName("IsDate") && ( ( xTextFieldPropSet->getPropertyValue( "IsDate" ) ) >>= bIsDate ) )
+ {
+ msDateTimeType = OUString::createFromAscii( bIsDate ? "<date>" : "<time>" );
+ }
+ }
+ }
+ }
+ }
if( sFieldName == "DateTime" || sFieldName == "Header"
|| sFieldName == "Footer" || sFieldName == "PageNumber" )
{
@@ -1684,6 +1710,13 @@ void SVGTextWriter::implWriteTextPortion( const Point& rPos,
SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
mrExport.GetDocHandler()->characters( msPageCount );
}
+ // This case handle Date or Time text field inserted by the user
+ // on both page/master page. It doesn't handle the standard Date/Time field.
+ else if ( !msDateTimeType.isEmpty() )
+ {
+ SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
+ mrExport.GetDocHandler()->characters( msDateTimeType );
+ }
else
{
SvXMLElementExport aSVGTspanElem( mrExport, XML_NAMESPACE_NONE, aXMLElemTspan, mbIWS, mbIWS );
diff --git a/filter/source/svg/svgwriter.hxx b/filter/source/svg/svgwriter.hxx
index e8396f16b886..541a39eaa843 100644
--- a/filter/source/svg/svgwriter.hxx
+++ b/filter/source/svg/svgwriter.hxx
@@ -249,6 +249,7 @@ class SVGTextWriter final
OUString msUrl;
OUString msHyperlinkIdList;
OUString msPageCount;
+ OUString msDateTimeType;
bool mbIsPlaceholderShape;
static const bool mbIWS = false;
vcl::Font maCurrentFont;