mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
Merge 1.1.0 changes back to master.
This commit is contained in:
@@ -18,11 +18,11 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* A directive which implements a color input field, leveraging the "Pickr"
|
||||
* color picker. If the "Picker" color picker cannot be used because it relies
|
||||
* on JavaScript features not supported by the browser (Internet Explorer), a
|
||||
* "guacInputColorUnavailable" event will be emitted up the scope, and this
|
||||
* A directive which implements a color input field. If the underlying color
|
||||
* picker implementation cannot be used due to a lack of browser support, this
|
||||
* directive will become read-only, functioning essentially as a color preview.
|
||||
*
|
||||
* @see colorPickerService
|
||||
*/
|
||||
angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
||||
|
||||
@@ -59,17 +59,12 @@ angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
||||
function guacInputColorController($scope, $element, $injector) {
|
||||
|
||||
// Required services
|
||||
var $q = $injector.get('$q');
|
||||
var $translate = $injector.get('$translate');
|
||||
var colorPickerService = $injector.get('colorPickerService');
|
||||
|
||||
/**
|
||||
* Whether the color picker ("Pickr") cannot be used. In general, all
|
||||
* browsers should support Pickr with the exception of Internet
|
||||
* Explorer.
|
||||
*
|
||||
* @type Boolean
|
||||
* @borrows colorPickerService.isAvailable()
|
||||
*/
|
||||
$scope.colorPickerUnavailable = false;
|
||||
$scope.isColorPickerAvailable = colorPickerService.isAvailable;
|
||||
|
||||
/**
|
||||
* Returns whether the color currently selected is "dark" in the sense
|
||||
@@ -102,98 +97,18 @@ angular.module('form').directive('guacInputColor', [function guacInputColor() {
|
||||
|
||||
};
|
||||
|
||||
// Init color picker after required translation strings are available
|
||||
$q.all({
|
||||
'save' : $translate('APP.ACTION_SAVE'),
|
||||
'cancel' : $translate('APP.ACTION_CANCEL')
|
||||
}).then(function stringsRetrieved(strings) {
|
||||
|
||||
try {
|
||||
|
||||
/**
|
||||
* An instance of the "Pickr" color picker, bound to the underlying
|
||||
* element of this directive.
|
||||
*
|
||||
* @type Pickr
|
||||
* Prompts the user to choose a color by displaying a color selection
|
||||
* dialog. If the user chooses a color, this directive's model is
|
||||
* automatically updated. If the user cancels the dialog, the model is
|
||||
* left untouched.
|
||||
*/
|
||||
var pickr = Pickr.create({
|
||||
|
||||
// Bind color picker to the underlying element of this directive
|
||||
el : $element[0],
|
||||
|
||||
// Wrap color picker dialog in Guacamole-specific class for
|
||||
// sake of additional styling
|
||||
appClass : 'guac-input-color-picker',
|
||||
|
||||
// Display color details as hex
|
||||
defaultRepresentation : 'HEX',
|
||||
|
||||
// Use "monolith" theme, as a nice balance between "nano" (does
|
||||
// not work in Internet Explorer) and "classic" (too big)
|
||||
theme : 'monolith',
|
||||
|
||||
// Leverage the container element as the button which shows the
|
||||
// picker, relying on our own styling for that button
|
||||
useAsButton : true,
|
||||
appendToBody : true,
|
||||
|
||||
// Do not include opacity controls
|
||||
lockOpacity : true,
|
||||
|
||||
// Include a selection of palette entries for convenience and
|
||||
// reference
|
||||
swatches : $scope.palette || [],
|
||||
|
||||
components: {
|
||||
|
||||
// Include hue and color preview controls
|
||||
preview : true,
|
||||
hue : true,
|
||||
|
||||
// Display only a text color input field and the save and
|
||||
// cancel buttons (no clear button)
|
||||
interaction: {
|
||||
input : true,
|
||||
save : true,
|
||||
cancel : true
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
// Use translation strings for buttons
|
||||
strings : strings
|
||||
|
||||
});
|
||||
|
||||
// Hide color picker after user clicks "cancel"
|
||||
pickr.on('cancel', function colorChangeCanceled() {
|
||||
pickr.hide();
|
||||
});
|
||||
|
||||
// Keep model in sync with changes to the color picker
|
||||
pickr.on('save', function colorChanged(color) {
|
||||
$scope.$evalAsync(function updateModel() {
|
||||
$scope.model = color.toHEXA().toString();
|
||||
});
|
||||
});
|
||||
|
||||
// Keep color picker in sync with changes to the model
|
||||
pickr.on('init', function pickrReady(color) {
|
||||
$scope.$watch('model', function modelChanged(model) {
|
||||
pickr.setColor(model);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// If the "Pickr" color picker cannot be loaded (Internet Explorer),
|
||||
// let the scope above us know
|
||||
catch (e) {
|
||||
$scope.colorPickerUnavailable = true;
|
||||
$scope.$emit('guacInputColorUnavailable', e);
|
||||
}
|
||||
|
||||
$scope.selectColor = function selectColor() {
|
||||
colorPickerService.selectColor($element[0], $scope.model, $scope.palette)
|
||||
.then(function colorSelected(color) {
|
||||
$scope.model = color;
|
||||
}, angular.noop);
|
||||
};
|
||||
|
||||
}];
|
||||
|
||||
|
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A service for prompting the user to choose a color using the "Pickr" color
|
||||
* picker. As the Pickr color picker might not be available if the JavaScript
|
||||
* features it requires are not supported by the browser (Internet Explorer),
|
||||
* the isAvailable() function should be used to test for usability.
|
||||
*/
|
||||
angular.module('form').provider('colorPickerService', function colorPickerServiceProvider() {
|
||||
|
||||
/**
|
||||
* A singleton instance of the "Pickr" color picker, shared by all users of
|
||||
* this service. Pickr does not initialize synchronously, nor is it
|
||||
* supported by all browsers. If Pickr is not yet initialized, or is
|
||||
* unsupported, this will be null.
|
||||
*
|
||||
* @type {Pickr}
|
||||
*/
|
||||
var pickr = null;
|
||||
|
||||
/**
|
||||
* Whether Pickr has completed initialization.
|
||||
*
|
||||
* @type {Boolean}
|
||||
*/
|
||||
var pickrInitComplete = false;
|
||||
|
||||
/**
|
||||
* The HTML element to provide to Pickr as the root element.
|
||||
*
|
||||
* @type {HTMLDivElement}
|
||||
*/
|
||||
var pickerContainer = document.createElement('div');
|
||||
pickerContainer.className = 'shared-color-picker';
|
||||
|
||||
/**
|
||||
* An instance of Deferred which represents an active request for the
|
||||
* user to choose a color. The promise associated with the Deferred will
|
||||
* be resolved with the chosen color once a color is chosen, and rejected
|
||||
* if the request is cancelled or Pickr is not available. If no request is
|
||||
* active, this will be null.
|
||||
*
|
||||
* @type {Deferred}
|
||||
*/
|
||||
var activeRequest = null;
|
||||
|
||||
/**
|
||||
* Resolves the current active request with the given color value. If no
|
||||
* color value is provided, the active request is rejected. If no request
|
||||
* is active, this function has no effect.
|
||||
*
|
||||
* @param {String} [color]
|
||||
* The color value to resolve the active request with.
|
||||
*/
|
||||
var completeActiveRequest = function completeActiveRequest(color) {
|
||||
if (activeRequest) {
|
||||
|
||||
// Hide color picker, if shown
|
||||
pickr.hide();
|
||||
|
||||
// Resolve/reject active request depending on value provided
|
||||
if (color)
|
||||
activeRequest.resolve(color);
|
||||
else
|
||||
activeRequest.reject();
|
||||
|
||||
// No active request
|
||||
activeRequest = null;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
pickr = Pickr.create({
|
||||
|
||||
// Bind color picker to the container element
|
||||
el : pickerContainer,
|
||||
|
||||
// Wrap color picker dialog in Guacamole-specific class for
|
||||
// sake of additional styling
|
||||
appClass : 'guac-input-color-picker',
|
||||
|
||||
'default' : '#000000',
|
||||
|
||||
// Display color details as hex
|
||||
defaultRepresentation : 'HEX',
|
||||
|
||||
// Use "monolith" theme, as a nice balance between "nano" (does
|
||||
// not work in Internet Explorer) and "classic" (too big)
|
||||
theme : 'monolith',
|
||||
|
||||
// Leverage the container element as the button which shows the
|
||||
// picker, relying on our own styling for that button
|
||||
useAsButton : true,
|
||||
appendToBody : true,
|
||||
|
||||
// Do not include opacity controls
|
||||
lockOpacity : true,
|
||||
|
||||
// Include a selection of palette entries for convenience and
|
||||
// reference
|
||||
swatches : [],
|
||||
|
||||
components: {
|
||||
|
||||
// Include hue and color preview controls
|
||||
preview : true,
|
||||
hue : true,
|
||||
|
||||
// Display only a text color input field and the save and
|
||||
// cancel buttons (no clear button)
|
||||
interaction: {
|
||||
input : true,
|
||||
save : true,
|
||||
cancel : true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Hide color picker after user clicks "cancel"
|
||||
pickr.on('cancel', function colorChangeCanceled() {
|
||||
completeActiveRequest();
|
||||
});
|
||||
|
||||
// Keep model in sync with changes to the color picker
|
||||
pickr.on('save', function colorChanged(color) {
|
||||
completeActiveRequest(color.toHEXA().toString());
|
||||
activeRequest = null;
|
||||
});
|
||||
|
||||
// Keep color picker in sync with changes to the model
|
||||
pickr.on('init', function pickrReady() {
|
||||
pickrInitComplete = true;
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// If the "Pickr" color picker cannot be loaded (Internet Explorer),
|
||||
// the available flag will remain set to false
|
||||
}
|
||||
|
||||
// Factory method required by provider
|
||||
this.$get = ['$injector', function colorPickerServiceFactory($injector) {
|
||||
|
||||
// Required services
|
||||
var $q = $injector.get('$q');
|
||||
var $translate = $injector.get('$translate');
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* Promise which is resolved when Pickr initialization has completed
|
||||
* and rejected if Pickr cannot be used.
|
||||
*
|
||||
* @type {Promise}
|
||||
*/
|
||||
var pickrPromise = (function getPickr() {
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
// Resolve promise when Pickr has completed initialization
|
||||
if (pickrInitComplete)
|
||||
deferred.resolve();
|
||||
else if (pickr)
|
||||
pickr.on('init', deferred.resolve);
|
||||
|
||||
// Reject promise if Pickr cannot be used at all
|
||||
else
|
||||
deferred.reject();
|
||||
|
||||
return deferred.promise;
|
||||
|
||||
})();
|
||||
|
||||
/**
|
||||
* Returns whether the underlying color picker (Pickr) can be used by
|
||||
* calling selectColor(). If the browser cannot support the color
|
||||
* picker, false is returned.
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* true if the underlying color picker can be used by calling
|
||||
* selectColor(), false otherwise.
|
||||
*/
|
||||
service.isAvailable = function isAvailable() {
|
||||
return !!pickr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Prompts the user to choose a color, returning the color chosen via a
|
||||
* Promise.
|
||||
*
|
||||
* @param {Element} element
|
||||
* The element that the user interacted with to indicate their
|
||||
* desire to choose a color.
|
||||
*
|
||||
* @param {String} current
|
||||
* The color that should be selected by default, in standard
|
||||
* 6-digit hexadecimal RGB format, including "#" prefix.
|
||||
*
|
||||
* @param {String[]} [palette]
|
||||
* An array of color choices which should be exposed to the user
|
||||
* within the color chooser for convenience. Each color must be in
|
||||
* standard 6-digit hexadecimal RGB format, including "#" prefix.
|
||||
*
|
||||
* @returns {Promise.<String>}
|
||||
* A Promise which is resolved with the color chosen by the user,
|
||||
* in standard 6-digit hexadecimal RGB format with "#" prefix, and
|
||||
* rejected if the selection operation was cancelled or the color
|
||||
* picker cannot be used.
|
||||
*/
|
||||
service.selectColor = function selectColor(element, current, palette) {
|
||||
|
||||
// Show picker once the relevant translation strings have been
|
||||
// retrieved and Pickr is ready for use
|
||||
return $q.all({
|
||||
'saveString' : $translate('APP.ACTION_SAVE'),
|
||||
'cancelString' : $translate('APP.ACTION_CANCEL'),
|
||||
'pickr' : pickrPromise
|
||||
}).then(function dependenciesReady(deps) {
|
||||
|
||||
// Cancel any active request
|
||||
completeActiveRequest();
|
||||
|
||||
// Reset state of color picker to provided parameters
|
||||
pickr.setColor(current);
|
||||
element.appendChild(pickerContainer);
|
||||
|
||||
// Assign translated strings to button text
|
||||
var pickrRoot = pickr.getRoot();
|
||||
pickrRoot.interaction.save.value = deps.saveString;
|
||||
pickrRoot.interaction.cancel.value = deps.cancelString;
|
||||
|
||||
// Replace all color swatches with the palette of colors given
|
||||
while (pickr.removeSwatch(0)) {}
|
||||
angular.forEach(palette, pickr.addSwatch.bind(pickr));
|
||||
|
||||
// Show color picker and wait for user to complete selection
|
||||
activeRequest = $q.defer();
|
||||
pickr.show();
|
||||
return activeRequest.promise;
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}];
|
||||
|
||||
});
|
@@ -220,10 +220,45 @@ angular.module('form').provider('formService', function formServiceProvider() {
|
||||
var $q = $injector.get('$q');
|
||||
var $templateRequest = $injector.get('$templateRequest');
|
||||
|
||||
/**
|
||||
* Map of module name to the injector instance created for that module.
|
||||
*
|
||||
* @type {Object.<String, injector>}
|
||||
*/
|
||||
var injectors = {};
|
||||
|
||||
var service = {};
|
||||
|
||||
service.fieldTypes = provider.fieldTypes;
|
||||
|
||||
/**
|
||||
* Given the name of a module, returns an injector instance which
|
||||
* injects dependencies within that module. A new injector may be
|
||||
* created and initialized if no such injector has yet been requested.
|
||||
* If the injector available to formService already includes the
|
||||
* requested module, that injector will simply be returned.
|
||||
*
|
||||
* @param {String} module
|
||||
* The name of the module to produce an injector for.
|
||||
*
|
||||
* @returns {injector}
|
||||
* An injector instance which injects dependencies for the given
|
||||
* module.
|
||||
*/
|
||||
var getInjector = function getInjector(module) {
|
||||
|
||||
// Use the formService's injector if possible
|
||||
if ($injector.modules[module])
|
||||
return $injector;
|
||||
|
||||
// If the formService's injector does not include the requested
|
||||
// module, create the necessary injector, reusing that injector for
|
||||
// future calls
|
||||
injectors[module] = injectors[module] || angular.injector(['ng', module]);
|
||||
return injectors[module];
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Compiles and links the field associated with the given name to the given
|
||||
* scope, producing a distinct and independent DOM Element which functions
|
||||
@@ -304,7 +339,7 @@ angular.module('form').provider('formService', function formServiceProvider() {
|
||||
|
||||
// Populate scope using defined controller
|
||||
if (fieldType.module && fieldType.controller) {
|
||||
var $controller = angular.injector(['ng', fieldType.module]).get('$controller');
|
||||
var $controller = getInjector(fieldType.module).get('$controller');
|
||||
$controller(fieldType.controller, {
|
||||
'$scope' : scope,
|
||||
'$element' : angular.element(fieldContainer.childNodes)
|
||||
|
@@ -1,8 +1,9 @@
|
||||
<div class="guac-input-color"
|
||||
ng-class="{
|
||||
'dark' : isDark(),
|
||||
'read-only' : colorPickerUnavailable
|
||||
'read-only' : !isColorPickerAvailable()
|
||||
}"
|
||||
ng-click="selectColor()"
|
||||
ng-style="{
|
||||
'background-color' : model
|
||||
}">
|
||||
|
Reference in New Issue
Block a user