blob: 900f3e1e0c263d25ce00d773f4836145ea554bb2 [file] [log] [blame]
/*
* Copyright (C) 2015 Devin Rousso <webkit@devinrousso.com>. 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.VisualStyleBackgroundPicker = class VisualStyleBackgroundPicker extends WI.VisualStylePropertyEditor
{
constructor(propertyNames, text, possibleValues, layoutReversed)
{
super(propertyNames, text, possibleValues, null, "background-picker", layoutReversed);
this._gradientSwatch = new WI.InlineSwatch(WI.InlineSwatch.Type.Gradient);
this._gradientSwatch.addEventListener(WI.InlineSwatch.Event.ValueChanged, this._gradientSwatchColorChanged, this);
this.contentElement.appendChild(this._gradientSwatch.element);
this._valueInputElement = document.createElement("input");
this._valueInputElement.classList.add("value-input");
this._valueInputElement.type = "url";
this._valueInputElement.placeholder = WI.UIString("Enter a URL");
this._valueInputElement.addEventListener("input", this.debounce(250)._valueInputValueChanged);
this.contentElement.appendChild(this._valueInputElement);
this._valueTypePickerElement = document.createElement("select");
this._valueTypePickerElement.classList.add("value-type-picker-select");
if (this._possibleValues.advanced)
this._valueTypePickerElement.title = WI.UIString("Option-click to show all values");
let imageOption = document.createElement("option");
imageOption.value = "url";
imageOption.text = WI.UIString("Image");
this._valueTypePickerElement.appendChild(imageOption);
let linearGradientOption = document.createElement("option");
linearGradientOption.value = "linear-gradient";
linearGradientOption.text = WI.UIString("Linear Gradient");
this._valueTypePickerElement.appendChild(linearGradientOption);
let radialGradientOption = document.createElement("option");
radialGradientOption.value = "radial-gradient";
radialGradientOption.text = WI.UIString("Radial Gradient");
this._valueTypePickerElement.appendChild(radialGradientOption);
let repeatingLinearGradientOption = document.createElement("option");
repeatingLinearGradientOption.value = "repeating-linear-gradient";
repeatingLinearGradientOption.text = WI.UIString("Repeating Linear Gradient");
this._valueTypePickerElement.appendChild(repeatingLinearGradientOption);
let repeatingRadialGradientOption = document.createElement("option");
repeatingRadialGradientOption.value = "repeating-radial-gradient";
repeatingRadialGradientOption.text = WI.UIString("Repeating Radial Gradient");
this._valueTypePickerElement.appendChild(repeatingRadialGradientOption);
this._valueTypePickerElement.appendChild(document.createElement("hr"));
this._createValueOptions(this._possibleValues.basic);
this._advancedValuesElements = null;
this._valueTypePickerElement.addEventListener("mousedown", this._keywordSelectMouseDown.bind(this));
this._valueTypePickerElement.addEventListener("change", this._handleKeywordChanged.bind(this));
this.contentElement.appendChild(this._valueTypePickerElement);
this._currentType = "url";
}
// Public
get value()
{
return this._valueInputElement.value;
}
set value(value)
{
if (!value || !value.length || value === this.value)
return;
const isKeyword = this.valueIsSupportedKeyword(value);
this._currentType = isKeyword ? value : value.substring(0, value.indexOf("("));
this._updateValueInput();
if (!isKeyword)
this._valueInputElement.value = value.substring(value.indexOf("(") + 1, value.length - 1);
this._valueTypePickerElement.value = this._currentType;
if (!this._currentType.includes("gradient"))
return;
this._updateGradient();
}
get synthesizedValue()
{
if (this.valueIsSupportedKeyword(this._currentType))
return this._currentType;
return this._currentType + "(" + this.value + ")";
}
// Protected
parseValue(text)
{
const validPrefixes = ["url", "linear-gradient", "radial-gradient", "repeating-linear-gradient", "repeating-radial-gradient"];
return validPrefixes.some((item) => text.startsWith(item)) ? [text, text] : null;
}
// Private
_updateValueInput()
{
const supportedKeyword = this.valueIsSupportedKeyword(this._currentType);
const gradientValue = this._currentType.includes("gradient");
this.contentElement.classList.toggle("gradient-value", !supportedKeyword && gradientValue);
this._valueInputElement.disabled = supportedKeyword;
if (supportedKeyword) {
this._valueInputElement.value = "";
this._valueInputElement.placeholder = WI.UIString("Using Keyword Value");
} else {
if (this._currentType === "image") {
this._valueInputElement.type = "url";
this._valueInputElement.placeholder = WI.UIString("Enter a URL");
} else if (gradientValue) {
this._valueInputElement.type = "text";
this._valueInputElement.placeholder = WI.UIString("Enter a Gradient");
}
}
}
_updateGradient()
{
const value = this.synthesizedValue;
if (!value || value === this._currentType)
return;
this._gradientSwatch.value = WI.Gradient.fromString(value);
}
_gradientSwatchColorChanged(event)
{
this.value = event.data.value.toString();
this._valueDidChange();
}
_valueInputValueChanged(event)
{
this._updateGradient();
this._valueDidChange();
}
_keywordSelectMouseDown(event)
{
if (event.altKey)
this._addAdvancedValues();
else if (!this._valueIsSupportedAdvancedKeyword(this.value))
this._removeAdvancedValues();
}
_handleKeywordChanged(event)
{
this._currentType = this._valueTypePickerElement.value;
this._updateValueInput();
this._updateGradient();
this._valueDidChange();
}
_createValueOptions(values)
{
let addedElements = [];
for (let key in values) {
let option = document.createElement("option");
option.value = key;
option.text = values[key];
this._valueTypePickerElement.appendChild(option);
addedElements.push(option);
}
return addedElements;
}
_addAdvancedValues()
{
if (this._advancedValuesElements)
return;
this._valueTypePickerElement.appendChild(document.createElement("hr"));
this._advancedValuesElements = this._createValueOptions(this._possibleValues.advanced);
}
_removeAdvancedValues()
{
if (!this._advancedValuesElements)
return;
this._valueTypePickerElement.removeChild(this._advancedValuesElements[0].previousSibling);
for (let element of this._advancedValuesElements)
this._valueTypePickerElement.removeChild(element);
this._advancedValuesElements = null;
}
_toggleTabbingOfSelectableElements(disabled)
{
let tabIndex = disabled ? "-1" : null;
this._valueInputElement.tabIndex = tabIndex;
this._valueTypePickerElement.tabIndex = tabIndex;
}
};