summaryrefslogtreecommitdiff
path: root/filter/source/svg/presentation_engine.js
diff options
context:
space:
mode:
Diffstat (limited to 'filter/source/svg/presentation_engine.js')
-rw-r--r--filter/source/svg/presentation_engine.js829
1 files changed, 692 insertions, 137 deletions
diff --git a/filter/source/svg/presentation_engine.js b/filter/source/svg/presentation_engine.js
index 9bd2936a019d..fa42b89b2f8e 100644
--- a/filter/source/svg/presentation_engine.js
+++ b/filter/source/svg/presentation_engine.js
@@ -32,6 +32,15 @@ var abs = Math.abs;
var now = Date.now;
/**
+ * polyfill for IE11
+ */
+if (!Math.trunc) {
+ Math.trunc = function (v) {
+ return v < 0 ? Math.ceil(v) : Math.floor(v);
+ };
+}
+
+/**
* set a timeout with a given scope
* @param {Function} fn
* @param {Number} timeout
@@ -359,7 +368,7 @@ function uniqueArray(src, key, sort) {
* @returns {String|Undefined} prefixed
*/
function prefixed(obj, property) {
- // tml: Have to check for obj being undefined
+ // tml: Have to check for obj being undefined
if (obj === undefined) {
return undefined;
}
@@ -754,7 +763,7 @@ function getDistance(p1, p2, props) {
var x = p2[props[0]] - p1[props[0]],
y = p2[props[1]] - p1[props[1]];
- return Math.sqrt((x * x) + (y * y));
+ return Math.hypot(x, y);
}
/**
@@ -2747,6 +2756,56 @@ function getElementsByProperty( node, name )
return elements;
}
+// User can hide / show the presentation content.
+// For that purpose, we change the background color of root node to either black or white.
+// To set it back to its original color (for showing the content back), we should have the initial background color saved somewhere to read back.
+// There may be no initial color at all, so the initial value of the saved initial is undefined.
+var rootNodeInitialBackgroundColor = undefined;
+
+function changeRootNodeBackgroundTo(color) {
+ if (rootNodeInitialBackgroundColor === undefined)
+ rootNodeInitialBackgroundColor = ROOT_NODE.style.backgroundColor;
+
+ if (color === 'initial')
+ ROOT_NODE.style.backgroundColor = rootNodeInitialBackgroundColor;
+ else
+ ROOT_NODE.style.backgroundColor = color;
+}
+
+var isContentHidden = false;
+var contentInitialVisibilityValues = null;
+
+function getInitialVisibilityValues() {
+ var list = ROOT_NODE.querySelectorAll('g');
+ contentInitialVisibilityValues = [];
+ for (var i = 0; i < list.length; i++) {
+ var temp = {};
+ temp.object = list[i];
+ temp.visibility = list[i].style.visibility;
+ contentInitialVisibilityValues.push(temp);
+ }
+}
+
+function hideShowContent(color) {
+ if (contentInitialVisibilityValues === null)
+ getInitialVisibilityValues();
+
+ if (isContentHidden) {
+ for (var i = 0; i < contentInitialVisibilityValues.length; i++)
+ contentInitialVisibilityValues[i].object.style.visibility = contentInitialVisibilityValues[i].visibility;
+
+ changeRootNodeBackgroundTo('initial');
+ isContentHidden = false;
+ }
+ else {
+ for (var i = 0; i < contentInitialVisibilityValues.length; i++)
+ contentInitialVisibilityValues[i].object.style.visibility = 'hidden';
+
+ changeRootNodeBackgroundTo(color);
+ isContentHidden = true;
+ }
+}
+
/** Event handler for key press.
*
* @param aEvt the event
@@ -2756,7 +2815,7 @@ function onKeyDown( aEvt )
if ( !aEvt )
aEvt = window.event;
- var code = aEvt.keyCode || aEvt.charCode;
+ var code = aEvt.keyCode || aEvt.charCode || aEvt.code;
// console.log('===> onKeyDown: ' + code);
@@ -2779,6 +2838,20 @@ function onKeyDown( aEvt )
// console.log(' now: ' + code);
}
+ else if (code === P_KEY) {
+ aEvt.preventDefault();
+ if (ROOT_NODE.style.cursor === 'pointer')
+ ROOT_NODE.style.cursor = 'default';
+ else
+ ROOT_NODE.style.cursor = 'pointer';
+ }
+ else if (code === W_KEY) {
+ hideShowContent('white');
+ }
+ else if (code === B_KEY) {
+ hideShowContent('black');
+ }
+
if( !processingEffect && keyCodeDictionary[currentMode] && keyCodeDictionary[currentMode][code] )
{
@@ -4434,8 +4507,10 @@ var aOOOAttrUsePositionedChars = 'use-positioned-chars';
var aOOOAttrSlide = 'slide';
var aOOOAttrMaster = 'master';
+var aOOOAttrDisplayName = 'display-name';
var aOOOAttrSlideDuration = 'slide-duration';
var aOOOAttrHasTransition = 'has-transition';
+var aOOOAttrHasCustomBackground = 'has-custom-background';
var aOOOAttrBackgroundVisibility = 'background-visibility';
var aOOOAttrMasterObjectsVisibility = 'master-objects-visibility';
var aOOOAttrPageNumberVisibility = 'page-number-visibility';
@@ -4453,10 +4528,13 @@ var aOOOAttrTextAdjust = 'text-adjust';
// element class names
var aClipPathGroupClassName = 'ClipPathGroup';
var aPageClassName = 'Page';
-var aSlideNumberClassName = 'Slide_Number';
-var aDateTimeClassName = 'Date/Time';
+var aSlideNumberClassName = 'PageNumber';
+var aDateTimeClassName = 'DateTime';
var aFooterClassName = 'Footer';
var aHeaderClassName = 'Header';
+var aDateClassName = 'Date';
+var aTimeClassName = 'Time';
+var aSlideNameClassName='PageName';
// Creating a namespace dictionary.
var NSS = {};
@@ -4491,7 +4569,10 @@ var END_KEY = 35; // end keycode
var ENTER_KEY = 13;
var SPACE_KEY = 32;
var ESCAPE_KEY = 27;
+var B_KEY = 66;
+var P_KEY = 80;
var Q_KEY = 81;
+var W_KEY = 87;
// Visibility Values
var HIDDEN = 0;
@@ -4771,15 +4852,6 @@ function getRandomInt( nMax )
return Math.floor( Math.random() * nMax );
}
-function isTextFieldElement( aElement ) // eslint-disable-line no-unused-vars
-{
- var sClassName = aElement.getAttribute( 'class' );
- return ( sClassName === aSlideNumberClassName ) ||
- ( sClassName === aFooterClassName ) ||
- ( sClassName === aHeaderClassName ) ||
- ( sClassName === aDateTimeClassName );
-}
-
/*********************
** Debug Utilities **
@@ -4908,6 +4980,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.
@@ -5025,6 +5099,8 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
else
this.nSlideNumber= -1;
+ this.slideName = this.element.getAttributeNS( NSS['ooo'], aOOOAttrDisplayName );
+
// Each slide element is double wrapped by <g> elements.
// The outer <g> element is responsible for
// the slide element visibility. In fact the visibility attribute has
@@ -5056,10 +5132,23 @@ function MetaSlide( sMetaSlideId, aMetaDoc )
assert( this.pageElement,
'MetaSlide: page element <' + this.slideId + '> not found.' );
+ // The slide custom background element and its id attribute.
+ this.backgroundElement = getElementByClassName( this.pageElement, 'Background' );
+ if( this.backgroundElement )
+ {
+ 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();
+ // We check if the slide has a custom background which overrides the one of the targeted master page
+ this.bHasCustomBackground = this.initHasCustomBackground();
+
// We initialize visibility properties of the target master page elements.
this.nAreMasterObjectsVisible = this.initVisibilityProperty( aOOOAttrMasterObjectsVisibility, VISIBLE );
this.nIsBackgroundVisible = this.initVisibilityProperty( aOOOAttrBackgroundVisibility, VISIBLE );
@@ -5079,6 +5168,9 @@ 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;
+ this.aTextFieldContentProviderSet[aSlideNameClassName] = new FixedTextProvider( this.slideName );
// We init the slide duration when automatic slide transition is enabled
this.fDuration = this.initSlideDuration();
@@ -5149,6 +5241,24 @@ 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 sClass = aPlaceholderElem.getAttribute('class');
+ var sFieldType = sClass.split(' ')[1];
+ if( sFieldType === aDateClassName)
+ aPlaceholderElem.textContent = new Date().toLocaleDateString();
+ else if( sFieldType === aTimeClassName )
+ aPlaceholderElem.textContent = new Date().toLocaleTimeString();
+ }
+},
+
initMasterPage : function()
{
var sMasterPageId = this.element.getAttributeNS( NSS['ooo'], aOOOAttrMaster );
@@ -5181,6 +5291,12 @@ initHasTransition : function()
return ( sHasTransition === 'true' );
},
+initHasCustomBackground : function()
+{
+ var sHasCustomBackground = this.element.getAttributeNS( NSS['ooo'], aOOOAttrHasCustomBackground );
+ return ( sHasCustomBackground === 'true' );
+},
+
initVisibilityProperty : function( aVisibilityAttribute, nDefaultValue )
{
var nVisibility = nDefaultValue;
@@ -5211,7 +5327,7 @@ initDateTimeFieldContentProvider : function( aOOOAttrDateTimeField )
var sClassName = getClassAttribute( aTextFieldElem );
if( sClassName == 'FixedDateTimeField' )
{
- aTextField = new FixedTextProvider( aTextFieldElem );
+ aTextField = new FixedTextByElementProvider( aTextFieldElem );
this.bIsDateTimeVariable = false;
}
else if( sClassName == 'VariableDateTimeField' )
@@ -5241,7 +5357,7 @@ initFixedTextFieldContentProvider : function( aOOOAttribute )
{
var aTextFieldElem = document.getElementById( sTextFieldId );
this.theMetaDoc.aTextFieldContentProviderSet[ nIndex ]
- = new FixedTextProvider( aTextFieldElem );
+ = new FixedTextByElementProvider( aTextFieldElem );
}
return this.theMetaDoc.aTextFieldContentProviderSet[ nIndex ];
},
@@ -5319,6 +5435,56 @@ getSlideAnimationsRoot : function()
}; // end MetaSlide prototype
+function removeRedundantParagraphFromTextFieldShape( aObject )
+{
+ var aTextElem = getElementByClassName( aObject, 'SVGTextShape' );
+ if( aTextElem )
+ {
+ var aPlaceholderElement = getElementsByClassName(aTextElem, 'PlaceholderText');
+ if( aPlaceholderElement )
+ {
+ var aTextParagraphSet = getElementsByClassName(aTextElem, 'TextParagraph');
+ // When the text field width is too small, the placeholder text spans several lines.
+ // We remove all text lines but the first one which is used as a placeholder.
+ // This is a workaround but it should work in the majority of cases.
+ // A complete solution needs to support svg text wrapping.
+ if( aTextParagraphSet.length > 1 )
+ {
+ var i = aTextParagraphSet.length;
+ while( i > 1 )
+ {
+ aTextElem.removeChild(aTextParagraphSet[i - 1]);
+ --i;
+ }
+ }
+ }
+ }
+}
+
+function getTextFieldType ( elem ) {
+ var sFieldType = null;
+ var sClass = elem.getAttribute('class');
+ if( sClass === 'TextShape' )
+ {
+ var aPlaceholderElement = getElementByClassName(elem, 'PlaceholderText');
+ if( aPlaceholderElement )
+ {
+ var sClassAttr = aPlaceholderElement.getAttribute('class');
+ var classes = sClassAttr.split(' ');
+ sFieldType = classes[1];
+ }
+ }
+ return sFieldType;
+}
+
+function isTextFieldByClassName ( sClassName )
+{
+ return sClassName.indexOf( aDateTimeClassName ) == 0 || sClassName.indexOf( aFooterClassName ) == 0
+ || sClassName.indexOf( aHeaderClassName ) == 0 || sClassName.indexOf( aSlideNumberClassName ) == 0
+ || sClassName.indexOf( aDateClassName ) == 0 || sClassName.indexOf( aTimeClassName ) == 0
+ || sClassName.indexOf( aSlideNameClassName ) == 0;
+}
+
/** Class MasterPage
* This class gives direct access to a master page element and to the following
* elements included in the master page:
@@ -5333,7 +5499,7 @@ getSlideAnimationsRoot : function()
* background image
* </g>
* <g class='BackgroundObjects'>
- * <g class='Date/Time'>
+ * <g class='DateTime'>
* date/time placeholder
* </g>
* <g class='Header'>
@@ -5342,7 +5508,7 @@ getSlideAnimationsRoot : function()
* <g class='Footer'>
* footer placeholder
* </g>
- * <g class='Slide_Number'>
+ * <g class='PageNumber'>
* slide number placeholder
* </g>
* shapes
@@ -5381,6 +5547,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' );
@@ -5394,13 +5561,33 @@ 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];
+ removeRedundantParagraphFromTextFieldShape( aObject );
+ 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 === aDateTimeClassName || sClass === aFooterClassName
+ || sClass === aHeaderClassName || sClass === aSlideNumberClassName)
+ {
+ sClass += '.Default';
+ aObject.setAttribute('class', sClass);
+ }
+ }
+ if( !sClass || !isTextFieldByClassName( sClass ) )
{
if( nCount === 0 )
{
@@ -5444,10 +5631,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
@@ -5492,70 +5683,101 @@ PlaceholderShape.prototype.isValid = function()
*/
PlaceholderShape.prototype.init = function()
{
-
var aTextFieldElement = getElementByClassName( this.masterPage.backgroundObjects, this.className );
if( aTextFieldElement )
{
- var aPlaceholderElement = getElementByClassName( aTextFieldElement, 'PlaceholderText' );
- if( aPlaceholderElement )
+ var aTextElem = getElementByClassName( aTextFieldElement, 'SVGTextShape' );
+ if( aTextElem )
{
- // Each text field element has an invisible rectangle that can be
- // regarded as the text field bounding box.
- // We exploit such a feature and the exported text adjust attribute
- // value in order to set up correctly the position and text
- // adjustment for the placeholder element.
- var aSVGRectElem = getElementByClassName( aTextFieldElement, 'BoundingBox' );
- if( aSVGRectElem )
+ var aPlaceholderElement = getElementByClassName(aTextElem, 'PlaceholderText');
+ if( aPlaceholderElement )
{
- var aRect = new Rectangle( aSVGRectElem );
- var sTextAdjust = getOOOAttribute( aTextFieldElement, aOOOAttrTextAdjust ) || 'left';
- var sTextAnchor, sX;
- if( sTextAdjust == 'left' )
- {
- sTextAnchor = 'start';
- sX = String( aRect.left );
- }
- else if( sTextAdjust == 'right' )
- {
- sTextAnchor = 'end';
- sX = String( aRect.right );
- }
- else if( sTextAdjust == 'center' )
+ // SVG 1.1 does not support text wrapping wrt a rectangle.
+ // When a text shape contains a placeholder, setting up the position
+ // of each text line doesn't work since the position is computed
+ // before replacing the placeholder text.
+ // Anyway each text shape has an invisible rectangle that can be
+ // regarded as the text shape bounding box.
+ // We exploit such a feature and the exported text adjust attribute
+ // value in order to set up correctly the position and text
+ // adjustment for the text shape content.
+ // We assume that once the real value has been substituted to
+ // the placeholder the resulting content is no more than a single line.
+ // So we remove from <tspan> elements used for setting up the
+ // position of text lines (class TextPosition) the 'x' and 'y' attribute.
+ // In the general case we would need to implement a function
+ // which is able to compute at which words the text shape content has
+ // to be wrapped.
+ var aSVGRectElem = getElementByClassName( aTextFieldElement, 'BoundingBox' );
+ if( aSVGRectElem )
{
- sTextAnchor = 'middle';
- var nMiddle = ( aRect.left + aRect.right ) / 2;
- sX = String( parseInt( String( nMiddle ) ) );
+ var aRect = new Rectangle( aSVGRectElem );
+ var sTextAdjust = getOOOAttribute( aTextFieldElement, aOOOAttrTextAdjust );
+ // the bbox of the text shape is indeed a bit larger, there is a bit of internal padding
+ var nMargin = 250; // 1000th mm
+ var sTextAnchor, sX;
+ if( sTextAdjust == 'left' )
+ {
+ sTextAnchor = 'start';
+ sX = String( Math.trunc( aRect.left + nMargin ) );
+ }
+ else if( sTextAdjust == 'right' )
+ {
+ sTextAnchor = 'end';
+ sX = String( Math.trunc( aRect.right - nMargin ) );
+ }
+ else if( sTextAdjust == 'center' )
+ {
+ sTextAnchor = 'middle';
+ var nMiddle = ( aRect.left + aRect.right ) / 2;
+ sX = String( parseInt( String( nMiddle ) ) );
+ }
+ if( sTextAnchor )
+ {
+ aTextElem.setAttribute( 'text-anchor', sTextAnchor );
+ if( sX )
+ aTextElem.setAttribute( 'x', sX );
+
+ var aTSpanElements = getElementsByClassName( aTextElem, 'TextPosition' );
+ if( aTSpanElements )
+ {
+ var i = 0;
+ for( ; i < aTSpanElements.length; ++i )
+ {
+ var aTSpanElem = aTSpanElements[i];
+ aTSpanElem.removeAttribute( 'x' );
+ if( i !== 0 )
+ aTSpanElem.removeAttribute( 'y' );
+ }
+ }
+ }
}
- if( sTextAnchor )
- aPlaceholderElement.setAttribute( 'text-anchor', sTextAnchor );
- if( sX )
- aPlaceholderElement.setAttribute( 'x', sX );
- }
- // date/time fields were not exported correctly when positioned chars are used
- if( this.masterPage.metaSlide.theMetaDoc.bIsUsePositionedChars )
- {
- // We remove all text lines but the first one used as placeholder.
- var aTextLineGroupElem = aPlaceholderElement.parentNode.parentNode;
- if( aTextLineGroupElem )
+ // date/time fields were not exported correctly when positioned chars are used
+ if( this.masterPage.metaSlide.theMetaDoc.bIsUsePositionedChars )
{
- // Just to be sure it is the element we are looking for.
- var sFontFamilyAttr = aTextLineGroupElem.getAttribute( 'font-family' );
- if( sFontFamilyAttr )
+ // We remove all text lines but the first one used as placeholder.
+ var aTextLineGroupElem = aPlaceholderElement.parentNode.parentNode;
+ if( aTextLineGroupElem )
{
- var aChildSet = getElementChildren( aTextLineGroupElem );
- if( aChildSet.length > 1 )
- var i = 1;
- for( ; i < aChildSet.length; ++i )
+ // Just to be sure it is the element we are looking for.
+ var sFontFamilyAttr = aTextLineGroupElem.getAttribute( 'font-family' );
+ if( sFontFamilyAttr )
{
- aTextLineGroupElem.removeChild( aChildSet[i] );
+ var aChildSet = getElementChildren( aTextLineGroupElem );
+ if( aChildSet.length > 1 )
+ var i = 1;
+ for( ; i < aChildSet.length; ++i )
+ {
+ aTextLineGroupElem.removeChild( aChildSet[i] );
+ }
}
}
}
+ this.textElement = aPlaceholderElement;
}
- this.element = aTextFieldElement;
- this.textElement = aPlaceholderElement;
}
+ this.element = aTextFieldElement;
}
};
@@ -5570,10 +5792,10 @@ PlaceholderShape.prototype.init = function()
* <use class='Background'> // reference to master page background element
* <g class='BackgroundObjects'>
* <use class='BackgroundObjectSubGroup'> // reference to the group of shapes on the master page that are below text fields
- * <g class='Slide_Number'> // a cloned element
+ * <g class='PageNumber'> // a cloned element
* ...
* </g>
- * <use class='Date/Time'> // reference to a clone
+ * <use class='DateTime'> // reference to a clone
* <use class='Footer'>
* <use class='Header'>
* <use class='BackgroundObjectSubGroup'> // reference to the group of shapes on the master page that are above text fields
@@ -5660,10 +5882,11 @@ MasterPageView.prototype.createElement = function()
// init the Background element
if( this.aMetaSlide.nIsBackgroundVisible )
{
+ var nBackgroundId = this.aMetaSlide.bHasCustomBackground ? this.aMetaSlide.backgroundId : this.aMasterPage.backgroundId;
this.aBackgroundElement = theDocument.createElementNS( NSS['svg'], 'use' );
this.aBackgroundElement.setAttribute( 'class', 'Background' );
setNSAttribute( 'xlink', this.aBackgroundElement,
- 'href', '#' + this.aMasterPage.backgroundId );
+ 'href', '#' + nBackgroundId );
// node linking
aMasterPageViewElement.appendChild( this.aBackgroundElement );
@@ -5690,57 +5913,71 @@ MasterPageView.prototype.createElement = function()
for( ; i < aBackgroundObjectSubGroupIdList.length; ++i )
{
sId = aBackgroundObjectSubGroupIdList[i];
- if( sId === aSlideNumberClassName )
+ if( sId.indexOf( aSlideNumberClassName ) == 0 )
{
// 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 + '.Default') ? 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 + '.Default' )
+ this.aSlideNumberFieldHandler = aSlideNumberFieldHandler;
}
}
- else if( sId === aDateTimeClassName )
+ else if( sId === aDateTimeClassName + '.Default' )
{
- // Date/Time field
+ // DateTime field
if( this.aMetaSlide.nIsDateTimeVisible )
{
this.aDateTimeFieldHandler =
- this.initTextFieldHandler( aDateTimeClassName, aPlaceholderShapeSet,
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
aTextFieldContentProviderSet, aDefsElement,
aTextFieldHandlerSet, sMasterSlideId );
}
}
- else if( sId === aFooterClassName )
+ else if( sId === aFooterClassName + '.Default' )
{
// Footer Field
if( this.aMetaSlide.nIsFooterVisible )
{
this.aFooterFieldHandler =
- this.initTextFieldHandler( aFooterClassName, aPlaceholderShapeSet,
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
aTextFieldContentProviderSet, aDefsElement,
aTextFieldHandlerSet, sMasterSlideId );
}
}
- else if( sId === aHeaderClassName )
+ else if( sId === aHeaderClassName + '.Default' )
{
// Header Field
if( this.aMetaSlide.nIsHeaderVisible )
{
this.aHeaderFieldHandler =
- this.initTextFieldHandler( aHeaderClassName, aPlaceholderShapeSet,
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
aTextFieldContentProviderSet, aDefsElement,
aTextFieldHandlerSet, sMasterSlideId );
}
}
+ else if( sId.indexOf( aDateTimeClassName ) == 0
+ || sId.indexOf( aFooterClassName ) == 0
+ || sId.indexOf( aHeaderClassName ) == 0
+ || sId.indexOf( aDateClassName ) == 0
+ || sId.indexOf( aTimeClassName ) == 0
+ || sId.indexOf( aSlideNameClassName ) == 0 )
+ {
+ this.initTextFieldHandler( sId, aPlaceholderShapeSet,
+ aTextFieldContentProviderSet, aDefsElement,
+ aTextFieldHandlerSet, sMasterSlideId );
+ }
else
{
// init BackgroundObjectSubGroup elements
@@ -5762,37 +5999,49 @@ MasterPageView.prototype.createElement = function()
};
MasterPageView.prototype.initTextFieldHandler =
- function( sClassName, aPlaceholderShapeSet, aTextFieldContentProviderSet,
+ function( sId, aPlaceholderShapeSet, aTextFieldContentProviderSet,
aDefsElement, aTextFieldHandlerSet, sMasterSlideId )
{
+ var sRefId = null;
var aTextFieldHandler = null;
- if( aPlaceholderShapeSet[sClassName] &&
- aPlaceholderShapeSet[sClassName].isValid()
- && aTextFieldContentProviderSet[sClassName] )
+ var sClassName = sId.split('.')[0];
+ var aPlaceholderShape = aPlaceholderShapeSet[sId];
+ var aTextFieldContentProvider = aTextFieldContentProviderSet[sClassName];
+ if( aPlaceholderShape && aPlaceholderShape.isValid()
+ && aTextFieldContentProvider )
{
- var sTextFieldContentProviderId = aTextFieldContentProviderSet[sClassName].sId;
+ var sTextFiedHandlerKey = aTextFieldContentProvider.sId + '.' + 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 ] )
+ if ( !aTextFieldHandlerSet[ sMasterSlideId ][ sTextFiedHandlerKey ] )
{
- aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ] =
- new TextFieldHandler( aPlaceholderShapeSet[sClassName],
- aTextFieldContentProviderSet[sClassName] );
- aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
+ aTextFieldHandlerSet[ sMasterSlideId ][ sTextFiedHandlerKey ] =
+ new TextFieldHandler( aPlaceholderShape,
+ aTextFieldContentProvider );
+ aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFiedHandlerKey ];
aTextFieldHandler.update();
aTextFieldHandler.appendTo( aDefsElement );
}
else
{
- aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFieldContentProviderId ];
+ aTextFieldHandler = aTextFieldHandlerSet[ sMasterSlideId ][ sTextFiedHandlerKey ];
}
+ sRefId = aTextFieldHandler.sId;
+ }
+ else if( aPlaceholderShape && aPlaceholderShape.element && aPlaceholderShape.element.firstElementChild
+ && !aPlaceholderShape.textElement && !aTextFieldContentProvider )
+ {
+ sRefId = aPlaceholderShape.element.firstElementChild.getAttribute('id');
+ }
+ if( sRefId )
+ {
// We create a <use> element referring to the cloned text field and
// append it to the field group element.
- var aTextFieldElement = document.createElementNS( NSS['svg'], 'use' );
- aTextFieldElement.setAttribute( 'class', sClassName );
- setNSAttribute( 'xlink', aTextFieldElement,
- 'href', '#' + aTextFieldHandler.sId );
+ var aTextFieldElement = document.createElementNS(NSS['svg'], 'use');
+ aTextFieldElement.setAttribute('class', sClassName);
+ setNSAttribute('xlink', aTextFieldElement,
+ 'href', '#' + sRefId);
// node linking
this.aBackgroundObjectsElement.appendChild( aTextFieldElement );
}
@@ -5955,25 +6204,32 @@ SlideNumberFieldHandler.prototype.update = function( nPageNumber )
* The svg element that contains the text content for one or more
* master slide text field.
*/
-function TextFieldContentProvider( aTextFieldContentElement )
+function TextFieldContentProvider()
{
- // This id is used as key for the theMetaDoc.aTextFieldHandlerSet object.
- if( aTextFieldContentElement )
- this.sId = aTextFieldContentElement.getAttribute( 'id' );
+ this.sId = TextFieldContentProvider.getUniqueId();
}
+/*** private methods ***/
+
+TextFieldContentProvider.CURR_UNIQUE_ID = 0;
+
+TextFieldContentProvider.getUniqueId = function()
+{
+ ++TextFieldContentProvider.CURR_UNIQUE_ID;
+ return TextFieldContentProvider.CURR_UNIQUE_ID;
+};
+
/** Class FixedTextProvider
* This class handles text field with a fixed text.
* The text content is provided by the 'text' property.
*
- * @param aTextFieldContentElement
- * The svg element that contains the text content for one or more
- * master slide text field.
+ * @param aText
+ * a string containing the text to be substituted.
*/
-function FixedTextProvider( aTextFieldContentElement )
+function FixedTextProvider( aText )
{
- FixedTextProvider.superclass.constructor.call( this, aTextFieldContentElement );
- this.text = aTextFieldContentElement.textContent;
+ FixedTextProvider.superclass.constructor.call( this );
+ this.text = aText;
}
extend( FixedTextProvider, TextFieldContentProvider );
@@ -5991,6 +6247,20 @@ FixedTextProvider.prototype.update = function( aFixedTextField )
aFixedTextField.setTextContent( this.text );
};
+/** Class FixedTextByElementProvider
+ * This class handles text field with a fixed text.
+ * The text content is provided by the 'text' property.
+ *
+ * @param aTextFieldContentElement
+ * The svg element that contains the text content for one or more
+ * master slide text field.
+ */
+function FixedTextByElementProvider( aTextFieldContentElement )
+{
+ FixedTextByElementProvider.superclass.constructor.call( this, aTextFieldContentElement.textContent );
+}
+extend( FixedTextByElementProvider, FixedTextProvider );
+
/** Class CurrentDateTimeProvider
* Provide the text content to a date/time field by generating the current
* date/time in the format specified by the 'dateTimeFormat' property.
@@ -5999,10 +6269,15 @@ 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;
+ }
}
extend( CurrentDateTimeProvider, TextFieldContentProvider );
@@ -6017,17 +6292,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;
};
@@ -6037,7 +6317,7 @@ CurrentDateTimeProvider.prototype.createDateTimeText = function( /*sDateTimeForm
*/
function SlideNumberProvider( nInitialSlideNumber, sPageNumberingType )
{
- SlideNumberProvider.superclass.constructor.call( this, null );
+ SlideNumberProvider.superclass.constructor.call( this );
this.nInitialSlideNumber = nInitialSlideNumber;
this.pageNumberingType = sPageNumberingType;
@@ -6841,6 +7121,8 @@ function matrixToString( aSVGMatrix )
// eslint-disable-next-line no-unused-vars
function numberParser( sValue )
{
+ if( typeof sValue !== 'string' )
+ return undefined;
if( sValue === '.' )
return undefined;
var reFloatNumber = /^[+-]?[0-9]*[.]?[0-9]*$/;
@@ -6853,6 +7135,9 @@ function numberParser( sValue )
function booleanParser( sValue )
{
+ if( typeof sValue !== 'string' )
+ return undefined;
+
sValue = sValue.toLowerCase();
if( sValue === 'true' )
return true;
@@ -6864,6 +7149,9 @@ function booleanParser( sValue )
function colorParser( sValue )
{
+ if( typeof sValue !== 'string' )
+ return undefined;
+
// The following 3 color functions are used in evaluating sValue string
// so don't remove them.
@@ -7797,6 +8085,7 @@ var ENUM_PROPERTY = 2;
var COLOR_PROPERTY = 3;
var STRING_PROPERTY = 4;
var BOOL_PROPERTY = 5;
+var TUPLE_NUMBER_PROPERTY = 6;
var aValueTypeOutMap = [ 'unknown', 'number', 'enum', 'color', 'string', 'boolean' ];
@@ -7814,6 +8103,14 @@ var aAttributeMap =
'get': 'getOpacity',
'set': 'setOpacity' },
+ 'scale': { 'type': TUPLE_NUMBER_PROPERTY,
+ 'get': 'getSize',
+ 'set': 'setSize' },
+
+ 'translate': { 'type': TUPLE_NUMBER_PROPERTY,
+ 'get': 'getPos',
+ 'set': 'setPos' },
+
'rotate': { 'type': NUMBER_PROPERTY,
'get': 'getRotationAngle',
'set': 'setRotationAngle' },
@@ -11382,6 +11679,70 @@ PropertyAnimationNode.prototype.createActivity = function()
+function isValidTransformation( sType )
+{
+ return ( sType === 'translate' || sType === 'scale' || sType === 'rotate'
+ || sType === 'skewX' || sType === 'skewY' );
+}
+
+function AnimationTransformNode( aAnimElem, aParentNode, aNodeContext )
+{
+ AnimationTransformNode.superclass.constructor.call( this, aAnimElem, aParentNode, aNodeContext );
+
+ this.sClassName = 'AnimationTransformNode';
+}
+extend( AnimationTransformNode, AnimationBaseNode3 );
+
+
+AnimationTransformNode.prototype.parseElement = function()
+{
+ var bRet = AnimationTransformNode.superclass.parseElement.call(this);
+
+ var aAnimElem = this.aElement;
+
+ // transformation type
+ var sTransformType = aAnimElem.getAttribute( 'svg:type' );
+ if( !isValidTransformation( sTransformType ) )
+ {
+ this.eCurrentState = INVALID_NODE;
+ log( 'AnimationTransformNode.parseElement: transformation type not found: ' + sTransformType );
+ }
+ else
+ {
+ this.sAttributeName = sTransformType;
+ }
+
+ return bRet;
+}
+
+AnimationTransformNode.prototype.createActivity = function()
+{
+ var aActivityParamSet = this.fillActivityParams();
+ var aAnimation;
+
+ if( this.getAttributeName() === 'scale' || this.getAttributeName() === 'translate' )
+ {
+ aAnimation = createPairPropertyAnimation( this.getAttributeName(),
+ this.getAnimatedElement(),
+ this.aNodeContext.aSlideWidth,
+ this.aNodeContext.aSlideHeight );
+
+ }
+ else
+ {
+ aAnimation = createPropertyAnimation( this.getAttributeName(),
+ this.getAnimatedElement(),
+ this.aNodeContext.aSlideWidth,
+ this.aNodeContext.aSlideHeight );
+ }
+
+ var aInterpolator = null; // createActivity will compute it;
+ return createActivity( aActivityParamSet, this, aAnimation, aInterpolator );
+};
+
+
+
+
function AnimationSetNode( aAnimElem, aParentNode, aNodeContext )
{
AnimationSetNode.superclass.constructor.call( this, aAnimElem, aParentNode, aNodeContext );
@@ -11680,10 +12041,8 @@ function createAnimationNode( aElement, aParentNode, aNodeContext )
aCreatedNode = new AnimationColorNode( aElement, aParentNode, aNodeContext );
break;
case ANIMATION_NODE_ANIMATETRANSFORM:
- //aCreatedNode = new AnimationTransformNode( aElement, aParentNode, aNodeContext );
- //break;
- log( 'createAnimationNode: ANIMATETRANSFORM not implemented' );
- return null;
+ aCreatedNode = new AnimationTransformNode( aElement, aParentNode, aNodeContext );
+ break;
case ANIMATION_NODE_TRANSITIONFILTER:
aCreatedNode = new AnimationTransitionFilterNode( aElement, aParentNode, aNodeContext );
break;
@@ -11806,6 +12165,41 @@ function createPropertyAnimation( sAttrName, aAnimatedElement, nWidth, nHeight )
+function createPairPropertyAnimation( sTransformType, aAnimatedElement, nWidth, nHeight )
+{
+ var aFunctorSet = aAttributeMap[ sTransformType ];
+ var sGetValueMethod = aFunctorSet.get;
+ var sSetValueMethod = aFunctorSet.set;
+
+ var aDefaultValue = [];
+ var aSizeReference = [];
+ if( sTransformType === 'scale' )
+ {
+ aDefaultValue[0] = aSizeReference[0] = aAnimatedElement.getBaseBBox().width;
+ aDefaultValue[1] = aSizeReference[1] = aAnimatedElement.getBaseBBox().height;
+ }
+ else if( sTransformType === 'translate' )
+ {
+ aDefaultValue[0] = aAnimatedElement.getBaseCenterX();
+ aDefaultValue[1] = aAnimatedElement.getBaseCenterY();
+ aSizeReference[0] = nWidth;
+ aSizeReference[1] = nHeight;
+ }
+ else
+ {
+ log( 'createPairPropertyAnimation: transform type is not handled' );
+ return null;
+ }
+
+ return new TupleAnimation( bind( aAnimatedElement, aAnimatedElement[ sGetValueMethod ] ),
+ bind( aAnimatedElement, aAnimatedElement[ sSetValueMethod ] ),
+ aDefaultValue,
+ aSizeReference );
+}
+
+
+
+
/** createShapeTransition
*
* @param aActivityParamSet
@@ -12005,6 +12399,45 @@ GenericAnimation.prototype.getUnderlyingValue = function()
+function TupleAnimation( aGetValueFunc, aSetValueFunc, aDefaultValue, aReferenceSize )
+{
+ TupleAnimation.superclass.constructor.call( this, aGetValueFunc, aSetValueFunc );
+ assert( aDefaultValue && aReferenceSize,
+ 'TupleAnimation constructor: default value functor and/or reference size are not valid' );
+
+ this.aDefaultValue = aDefaultValue;
+ this.aReferenceSize = aReferenceSize;
+}
+extend( TupleAnimation, GenericAnimation );
+
+TupleAnimation.prototype.perform = function( aNormValue )
+{
+ assert(aNormValue.length === this.aReferenceSize.length);
+
+ var aValue = [];
+ for( var i = 0; i < aNormValue.length; ++i )
+ {
+ aValue.push( aNormValue[i] * this.aReferenceSize[i] );
+ }
+
+ this.aSetValueFunc( aValue );
+};
+
+TupleAnimation.prototype.getUnderlyingValue = function()
+{
+ var aValue = this.aGetValueFunc();
+ assert(aValue.length === this.aReferenceSize.length);
+
+ var aNormValue = [];
+ for( var i = 0; i < aValue.length; ++i )
+ {
+ aNormValue.push( aValue[i] / this.aReferenceSize[i] );
+ }
+
+ return aNormValue;
+};
+
+
function HSLAnimationWrapper( aColorAnimation )
{
@@ -14322,6 +14755,11 @@ AnimatedElement.prototype.getY = function()
return this.nCenterY;
};
+AnimatedElement.prototype.getPos = function()
+{
+ return [this.getX(), this.getY()];
+};
+
AnimatedElement.prototype.getWidth = function()
{
return this.nScaleFactorX * this.getBaseBBox().width;
@@ -14332,6 +14770,11 @@ AnimatedElement.prototype.getHeight = function()
return this.nScaleFactorY * this.getBaseBBox().height;
};
+AnimatedElement.prototype.getSize = function()
+{
+ return [this.getWidth(), this.getHeight()];
+};
+
AnimatedElement.prototype.updateTransformAttribute = function()
{
this.aTransformAttrList = this.aActiveElement.transform.baseVal;
@@ -14361,12 +14804,27 @@ AnimatedElement.prototype.setY = function( nNewCenterY )
this.nCenterY = nNewCenterY;
};
+AnimatedElement.prototype.setPos = function( aNewPos )
+{
+ var nNewCenterX = aNewPos[0];
+ var nNewCenterY = aNewPos[1];
+
+ if( nNewCenterX === this.nCenterX && nNewCenterY === this.nCenterY ) return;
+
+ this.aTransformAttrList = this.aActiveElement.transform.baseVal;
+ this.aTransformAttr = this.aTransformAttrList.getItem( 0 );
+ this.aTMatrix = this.aTransformAttr.matrix.translate( nNewCenterX - this.nCenterX, nNewCenterY - this.nCenterY );
+ this.aTransformAttr.setMatrix( this.aTMatrix );
+ this.nCenterX = nNewCenterX;
+ this.nCenterY = nNewCenterY;
+};
+
AnimatedElement.prototype.setWidth = function( nNewWidth )
{
ANIMDBG.print( 'AnimatedElement.setWidth: nNewWidth = ' + nNewWidth );
if( nNewWidth < 0 )
{
- log('AnimatedElement(' + this.getId() + ').setWidth: negative height!');
+ log('AnimatedElement(' + this.getId() + ').setWidth: negative width!');
nNewWidth = 0;
}
@@ -14411,6 +14869,43 @@ AnimatedElement.prototype.setHeight = function( nNewHeight )
this.nScaleFactorY = nScaleFactorY;
};
+AnimatedElement.prototype.setSize= function( aNewSize )
+{
+ var nNewWidth = aNewSize[0];
+ var nNewHeight = aNewSize[1];
+ ANIMDBG.print( 'AnimatedElement.setSize: = [' + nNewWidth + ',' + nNewHeight + ']');
+ if( nNewWidth < 0 )
+ {
+ log('AnimatedElement(' + this.getId() + ').setSize: negative width!');
+ nNewWidth = 0;
+ }
+ if( nNewHeight < 0 )
+ {
+ log('AnimatedElement(' + this.getId() + ').setSize: negative height!');
+ nNewHeight = 0;
+ }
+
+ var nBaseWidth = this.getBaseBBox().width;
+ var nScaleFactorX = nNewWidth / nBaseWidth;
+ if( nScaleFactorX < 1e-5 ) nScaleFactorX = 1e-5;
+
+ var nBaseHeight = this.getBaseBBox().height;
+ var nScaleFactorY = nNewHeight / nBaseHeight;
+ if( nScaleFactorY < 1e-5 ) nScaleFactorY = 1e-5;
+
+ if( nScaleFactorX == this.nScaleFactorX && nScaleFactorY == this.nScaleFactorY ) return;
+
+ this.aTMatrix = document.documentElement.createSVGMatrix()
+ .translate( this.nCenterX, this.nCenterY )
+ .rotate(this.nRotationAngle)
+ .scaleNonUniform( nScaleFactorX, nScaleFactorY )
+ .translate( -this.nBaseCenterX, -this.nBaseCenterY );
+ this.updateTransformAttribute();
+
+ this.nScaleFactorX = nScaleFactorX;
+ this.nScaleFactorY = nScaleFactorY;
+};
+
AnimatedElement.prototype.getOpacity = function()
{
return this.aActiveElement.getAttribute( 'opacity' );
@@ -14573,7 +15068,7 @@ function AnimatedTextElement( aElement, aEventMultiplexer )
}
var aTextShapeElement = aElement.parentNode;
sTextType = aTextShapeElement.getAttribute( 'class' );
- if( sTextType !== 'TextShape' )
+ if( sTextType !== 'SVGTextShape' )
{
log( 'AnimatedTextElement: element parent is not a text shape.' );
return;
@@ -14615,7 +15110,7 @@ function AnimatedTextElement( aElement, aEventMultiplexer )
if( aBulletPlaceholderElem )
{
var sId = aBulletPlaceholderElem.getAttribute( 'id' );
- sId = 'bullet-char(' + sId + ')';
+ sId = 'bullet-char-' + sId;
aBulletCharElem = theDocument.getElementById( sId );
if( aBulletCharElem )
{
@@ -16144,6 +16639,17 @@ aInterpolatorHandler.aLerpFunctorMap[ CALC_MODE_LINEAR ][ COLOR_PROPERTY ][ COLO
};
};
+aInterpolatorHandler.aLerpFunctorMap[ CALC_MODE_LINEAR ][ TUPLE_NUMBER_PROPERTY ] =
+ function ( aFrom, aTo, nT )
+ {
+ var aRes = [];
+ for( var i = 0; i < aFrom.length; ++i )
+ {
+ aRes.push( ( 1.0 - nT )* aFrom[i] + nT * aTo[i] );
+ }
+ return aRes;
+ };
+
@@ -16311,6 +16817,36 @@ aOperatorSetMap[ STRING_PROPERTY ] = aOperatorSetMap[ ENUM_PROPERTY ];
// bool operators
aOperatorSetMap[ BOOL_PROPERTY ] = aOperatorSetMap[ ENUM_PROPERTY ];
+// tuple number operators
+aOperatorSetMap[ TUPLE_NUMBER_PROPERTY ] = {};
+
+aOperatorSetMap[ TUPLE_NUMBER_PROPERTY ].equal = function( a, b )
+{
+ assert( a.length === b.length, 'Tuples length mismatch.' );
+ return ( a.toString() === b.toString() );
+};
+
+aOperatorSetMap[ TUPLE_NUMBER_PROPERTY ].add = function( a, b )
+{
+ assert( a.length === b.length, 'Tuples length mismatch.' );
+ var r = [];
+ for( var i = 0; i < a.length; ++i )
+ {
+ r.push(a[i] + b[i]);
+ }
+ return r;
+};
+
+aOperatorSetMap[ TUPLE_NUMBER_PROPERTY ].scale = function( k, v )
+{
+ var r = [];
+ for( var i = 0; i < v.length; ++i )
+ {
+ r.push(k * v[i]);
+ }
+ return r;
+};
+
@@ -17720,6 +18256,22 @@ function extractAttributeValues( eValueType, aValueList, aValueSet, aBBox, nSlid
aValueList.push( aValue );
}
break;
+ case TUPLE_NUMBER_PROPERTY :
+ for( i = 0; i < aValueSet.length; ++i )
+ {
+ if( typeof aValueSet[i] === 'string' )
+ {
+ var aTuple = aValueSet[i].split(',');
+ aValue = [];
+ evalValuesAttribute(aValue, aTuple, aBBox, nSlideWidth, nSlideHeight);
+ aValueList.push(aValue);
+ }
+ else
+ {
+ aValueList.push( undefined );
+ }
+ }
+ break;
default:
log( 'createValueListActivity: unexpected value type: ' + eValueType );
}
@@ -17742,9 +18294,12 @@ function evalValuesAttribute( aValueList, aValueSet, aBBox, nSlideWidth, nSlideH
for( var i = 0; i < aValueSet.length; ++i )
{
var sValue = aValueSet[i];
- sValue = sValue.replace(reMath, 'Math.$&');
- sValue = sValue.replace(/pi(?!\w)/g, 'Math.PI');
- sValue = sValue.replace(/e(?!\w)/g, 'Math.E');
+ if(sValue)
+ {
+ sValue = sValue.replace(reMath, 'Math.$&');
+ sValue = sValue.replace(/pi(?!\w)/g, 'Math.PI');
+ sValue = sValue.replace(/e(?!\w)/g, 'Math.E');
+ }
var aValue = eval( sValue );
aValueList.push( aValue );
}
@@ -18430,8 +18985,8 @@ SlideShow.prototype.exitSlideShowInApp = function()
{
if (window.webkit !== undefined &&
window.webkit.messageHandlers !== undefined &&
- window.webkit.messageHandlers.lool !== undefined)
- window.webkit.messageHandlers.lool.postMessage('EXITSLIDESHOW', '*');
+ window.webkit.messageHandlers.lok !== undefined)
+ window.webkit.messageHandlers.lok.postMessage('EXITSLIDESHOW', '*');
}
SlideShow.prototype.displaySlide = function( nNewSlide, bSkipSlideTransition )