blob: cf916445ef4e3b265561010766461c7ed39d669f [file] [log] [blame]
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
WI.SpreadsheetCSSStyleDeclarationEditor = class SpreadsheetCSSStyleDeclarationEditor extends WI.View
{
constructor(delegate, style)
{
super();
this.element.classList.add(WI.SpreadsheetCSSStyleDeclarationEditor.StyleClassName);
this._delegate = delegate;
this.style = style;
}
// Public
layout()
{
super.layout();
this.element.removeChildren();
let properties = this._propertiesToRender;
this.element.classList.toggle("no-properties", !properties.length);
this._propertyViews = [];
for (let index = 0; index < properties.length; index++) {
let property = properties[index];
let propertyView = new WI.SpreadsheetStyleProperty(this, property, index);
this.element.append(propertyView.element);
this._propertyViews.push(propertyView);
}
}
get style()
{
return this._style;
}
set style(style)
{
if (this._style === style)
return;
if (this._style)
this._style.removeEventListener(WI.CSSStyleDeclaration.Event.PropertiesChanged, this._propertiesChanged, this);
this._style = style || null;
if (this._style)
this._style.addEventListener(WI.CSSStyleDeclaration.Event.PropertiesChanged, this._propertiesChanged, this);
this.needsLayout();
}
startEditingFirstProperty()
{
if (this._propertyViews.length)
this._propertyViews[0].nameTextField.startEditing();
else {
let index = 0;
this._addBlankProperty(index);
}
}
startEditingLastProperty()
{
let lastProperty = this._propertyViews.lastValue;
if (lastProperty)
lastProperty.valueTextField.startEditing();
else {
let index = 0;
this._addBlankProperty(index);
}
}
spreadsheetCSSStyleDeclarationEditorFocusMoved({direction, movedFromProperty, willRemoveProperty})
{
let movedFromIndex = this._propertyViews.indexOf(movedFromProperty);
console.assert(movedFromIndex !== -1, "Property doesn't exist, focusing on a selector as a fallback.");
if (movedFromIndex === -1) {
if (this._style.selectorEditable)
this._delegate.cssStyleDeclarationTextEditorStartEditingRuleSelector();
return;
}
if (direction === "forward") {
// Move from the value to the next property's name.
let index = movedFromIndex + 1;
if (index < this._propertyViews.length)
this._propertyViews[index].nameTextField.startEditing();
else {
if (willRemoveProperty) {
// Move from the last value in the rule to the next rule's selector.
let reverse = false;
this._delegate.cssStyleDeclarationEditorStartEditingAdjacentRule(reverse);
} else
this._addBlankProperty(movedFromIndex);
}
} else {
let index = movedFromIndex - 1;
if (index < 0) {
// Move from the first property's name to the rule's selector.
if (this._style.selectorEditable)
this._delegate.cssStyleDeclarationTextEditorStartEditingRuleSelector();
} else {
// Move from the property's name to the previous property's value.
let valueTextField = this._propertyViews[index].valueTextField;
if (valueTextField)
valueTextField.startEditing();
}
}
}
spreadsheetStylePropertyRemoved(propertyView)
{
this._propertyViews.remove(propertyView);
}
// Private
get _propertiesToRender()
{
if (this._style._styleSheetTextRange)
return this._style.allVisibleProperties;
return this._style.allProperties;
}
_addBlankProperty(afterIndex)
{
let blankProperty = this._style.newBlankProperty(afterIndex);
const newlyAdded = true;
let propertyView = new WI.SpreadsheetStyleProperty(this, blankProperty, blankProperty.index, newlyAdded);
this.element.append(propertyView.element);
this._propertyViews.push(propertyView);
propertyView.nameTextField.startEditing();
}
_isFocused()
{
let focusedElement = document.activeElement;
if (!focusedElement || focusedElement.tagName === "BODY")
return false;
return focusedElement.isSelfOrDescendant(this.element);
}
_propertiesChanged(event)
{
if (!this._isFocused())
this.needsLayout();
}
};
WI.SpreadsheetCSSStyleDeclarationEditor.StyleClassName = "spreadsheet-style-declaration-editor";