mirror of
https://github.com/google/blockly.git
synced 2026-01-07 09:00:11 +01:00
Enable selection of “no colour” on categories.
Near complete rewrite of colour picker for Blockly Factory. * Drop IE6 support. * Flip picker as needed so it doesn’t go offscreen. * Add support for no colour. * Factor CSS out of JS. * Provide palette of our standard colours.
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 43 B |
46
demos/blockfactory/cp.css
Normal file
46
demos/blockfactory/cp.css
Normal file
@@ -0,0 +1,46 @@
|
||||
.cp_swatch {
|
||||
border: outset 3px #888;
|
||||
display: inline-block;
|
||||
font-family: sans-serif;
|
||||
height: 20px;
|
||||
line-height: 1.4;
|
||||
margin: 1px;
|
||||
text-align: center;
|
||||
width: 30px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
#cp_popup {
|
||||
cursor: default;
|
||||
font-family: sans-serif;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#cp_popup>table {
|
||||
border: 2px solid #808080;
|
||||
background-color: #808080;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
#cp_popup>table>tbody>tr>td {
|
||||
border: 1px solid #808080;
|
||||
background-color: #fff;
|
||||
width: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#cp_popup>table>tbody>tr>td>div {
|
||||
border: 1px solid #808080;
|
||||
}
|
||||
|
||||
#cp_popup>table>tbody>tr>td>div:hover {
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
#cp_popup>table>tbody>tr>td>div.cp_current {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Colour Picker v1.1
|
||||
* Colour Picker v2.0
|
||||
*
|
||||
* Copyright 2006 Neil Fraser
|
||||
* https://neil.fraser.name/software/colourpicker/
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
// Include at the top of your page:
|
||||
// <script src="cp.js"></script>
|
||||
// <link rel="stylesheet" href="cp.css">
|
||||
// Call with:
|
||||
// <input name="mycolour" id="mycolour" value="ff00ff">
|
||||
// <script>
|
||||
@@ -32,166 +33,158 @@ var cp_grid = [
|
||||
['999999', 'cc0000', 'ff6600', 'ffcc33', 'ffcc00', '33cc00', '00cccc', '3366ff', '6633ff', 'cc33cc'],
|
||||
['666666', '990000', 'cc6600', 'cc9933', '999900', '009900', '339999', '3333ff', '6600cc', '993399'],
|
||||
['333333', '660000', '993300', '996633', '666600', '006600', '336666', '000099', '333399', '663366'],
|
||||
['000000', '330000', '663300', '663333', '333300', '003300', '003333', '000066', '330099', '330033']];
|
||||
['000000', '330000', '663300', '663333', '333300', '003300', '003333', '000066', '330099', '330033'],
|
||||
['']
|
||||
];
|
||||
|
||||
var cp_dom = null;
|
||||
var cp_caller = null;
|
||||
var cp_defaultcolour = 'ffffff';
|
||||
var cp_closePID = null;
|
||||
var cp_popupDom = null;
|
||||
var cp_activeSwatch = null;
|
||||
var cp_closePid = null;
|
||||
|
||||
function cp_init(id) {
|
||||
// Hide the form element, and replace it with a colour box.
|
||||
var obj = document.getElementById(id);
|
||||
if (!obj) {
|
||||
alert('Colour picker can\'t find "' + id + '"');
|
||||
return;
|
||||
var input = document.getElementById(id);
|
||||
if (!input) {
|
||||
throw Error('Colour picker can\'t find "' + id + '"');
|
||||
}
|
||||
if (!cp_hex2rgb(obj.value)) {
|
||||
alert('Colour picker can\'t parse colour code in "' + id + '"');
|
||||
return;
|
||||
}
|
||||
if (!obj.cp_box) {
|
||||
obj.type = 'hidden';
|
||||
if (!input.cp_swatch) {
|
||||
// Hide the input.
|
||||
input.type = 'hidden';
|
||||
// <img style="background-color: #ff0000; border: outset 3px #888;"
|
||||
// src="1x1.gif" height=20 width=30>
|
||||
var box = document.createElement('img');
|
||||
box.style.border = 'outset 3px #888';
|
||||
box.src = '1x1.gif';
|
||||
box.height = 20;
|
||||
box.width = 30;
|
||||
box.label = id;
|
||||
box.onclick = new Function('cp_open(this)');
|
||||
box.onmouseover = cp_cancelclose;
|
||||
box.onmouseout = cp_closesoon;
|
||||
obj.parentNode.insertBefore(box, obj);
|
||||
obj.cp_box = box;
|
||||
// src="1x1.gif" height=20 width=30 class="cp_swatch">
|
||||
var swatch = document.createElement('span');
|
||||
swatch.className = 'cp_swatch';
|
||||
swatch.addEventListener('click', cp_open);
|
||||
swatch.addEventListener('mouseover', cp_cancelclose);
|
||||
swatch.addEventListener('mouseout', cp_closesoon);
|
||||
input.parentNode.insertBefore(swatch, input);
|
||||
// Cross-link the swatch and input.
|
||||
swatch.cp_input = input;
|
||||
input.cp_swatch = swatch;
|
||||
}
|
||||
obj.cp_box.style.backgroundColor = '#' + obj.value;
|
||||
cp_updateSwatch(input.cp_swatch);
|
||||
}
|
||||
|
||||
function cp_open(caller) {
|
||||
function cp_updateSwatch(swatch) {
|
||||
var colour = swatch.cp_input.value;
|
||||
if (colour) {
|
||||
swatch.style.backgroundColor = '#' + colour;
|
||||
swatch.textContent = '\xa0';
|
||||
} else {
|
||||
swatch.style.backgroundColor = '#fff';
|
||||
swatch.innerHTML = 'X';
|
||||
}
|
||||
}
|
||||
|
||||
function cp_open(e) {
|
||||
// Create a table of colours.
|
||||
if (cp_dom) {
|
||||
if (cp_popupDom) {
|
||||
cp_close();
|
||||
return;
|
||||
}
|
||||
cp_caller = caller;
|
||||
// alert(document.getElementById(caller.label));
|
||||
cp_defaultcolour = document.getElementById(caller.label).value;
|
||||
cp_activeSwatch = e.currentTarget;
|
||||
var currentColour = cp_activeSwatch.cp_input.value.toLowerCase();
|
||||
var element = cp_activeSwatch;
|
||||
var posX = 0;
|
||||
var posY = caller.offsetHeight;
|
||||
while (caller) {
|
||||
posX += caller.offsetLeft;
|
||||
posY += caller.offsetTop;
|
||||
caller = caller.offsetParent;
|
||||
var posY = element.offsetHeight;
|
||||
while (element) {
|
||||
posX += element.offsetLeft;
|
||||
posY += element.offsetTop;
|
||||
element = element.offsetParent;
|
||||
}
|
||||
cp_dom = document.createElement('div');
|
||||
cp_dom.id = 'colourpicker';
|
||||
cp_popupDom = document.createElement('div');
|
||||
cp_popupDom.id = 'cp_popup';
|
||||
var table = document.createElement('table');
|
||||
table.setAttribute('border', '1');
|
||||
table.style.backgroundColor = '#808080';
|
||||
table.onmouseover = cp_cancelclose;
|
||||
table.onmouseout = cp_closesoon;
|
||||
var tbody = document.createElement('tbody'); // IE 6 needs this.
|
||||
var row, cell;
|
||||
table.addEventListener('mouseover', cp_cancelclose);
|
||||
table.addEventListener('mouseout', cp_closesoon);
|
||||
table.addEventListener('click', cp_onclick);
|
||||
var tbody = document.createElement('tbody');
|
||||
var row, cell, div;
|
||||
for (var y = 0; y < cp_grid.length; y++) {
|
||||
row = document.createElement('tr');
|
||||
tbody.appendChild(row);
|
||||
for (var x = 0; x < cp_grid[y].length; x++) {
|
||||
var colour = cp_grid[y][x];
|
||||
if (colour === undefined) continue;
|
||||
cell = document.createElement('td');
|
||||
row.appendChild(cell);
|
||||
cell.style.backgroundColor = '#' + cp_grid[y][x];
|
||||
cell.label = cp_grid[y][x];
|
||||
cell.style.border = 'solid 2px #' + cell.label;
|
||||
cell.onmouseover = cp_onmouseover;
|
||||
cell.onmouseout = cp_onmouseout;
|
||||
cell.onclick = cp_onclick;
|
||||
cell.innerHTML = '<img src="1x1.gif" height=16 width=16>';
|
||||
if (cp_defaultcolour.toLowerCase() == cp_grid[y][x].toLowerCase()) {
|
||||
cell.onmouseover();
|
||||
cell.onmouseout();
|
||||
div = document.createElement('div');
|
||||
cell.appendChild(div);
|
||||
cell.cp_colour = colour;
|
||||
if (colour) {
|
||||
div.style.backgroundColor = '#' + colour;
|
||||
div.innerHTML = '\xa0';
|
||||
} else {
|
||||
div.innerHTML = 'X';
|
||||
}
|
||||
if (currentColour == colour.toLowerCase()) {
|
||||
div.className = 'cp_current'
|
||||
}
|
||||
}
|
||||
}
|
||||
table.appendChild(tbody);
|
||||
cp_dom.appendChild(table);
|
||||
cp_popupDom.appendChild(table);
|
||||
|
||||
cp_dom.style.position = 'absolute';
|
||||
cp_dom.style.left = '0';
|
||||
cp_dom.style.top = '0';
|
||||
cp_dom.style.visibility = 'hidden';
|
||||
document.body.appendChild(cp_dom);
|
||||
document.body.appendChild(cp_popupDom);
|
||||
// Don't widen the screen.
|
||||
if (posX + cp_dom.offsetWidth > document.body.offsetWidth) {
|
||||
posX = document.body.offsetWidth - cp_dom.offsetWidth;
|
||||
var rightOverhang = (posX + cp_popupDom.offsetWidth) -
|
||||
(window.innerWidth + window.scrollX) + 15; // Scrollbar is 15px.
|
||||
if (rightOverhang > 0) {
|
||||
posX -= rightOverhang;
|
||||
}
|
||||
cp_dom.style.left = posX + 'px';
|
||||
cp_dom.style.top = posY + 'px';
|
||||
cp_dom.style.visibility = 'visible';
|
||||
// Flip to above swatch if no room below.
|
||||
if (posY + cp_popupDom.offsetHeight >= window.innerHeight + window.scrollY) {
|
||||
posY -= cp_popupDom.offsetHeight + cp_activeSwatch.offsetHeight;
|
||||
if (posY < window.scrollY) {
|
||||
posY = window.scrollY;
|
||||
}
|
||||
}
|
||||
cp_popupDom.style.left = posX + 'px';
|
||||
cp_popupDom.style.top = posY + 'px';
|
||||
}
|
||||
|
||||
function cp_close() {
|
||||
// Close the table now.
|
||||
cp_cancelclose();
|
||||
if (cp_dom)
|
||||
document.body.removeChild(cp_dom)
|
||||
cp_dom = null;
|
||||
cp_caller = null;
|
||||
if (cp_popupDom) {
|
||||
document.body.removeChild(cp_popupDom)
|
||||
}
|
||||
cp_popupDom = null;
|
||||
cp_activeSwatch = null;
|
||||
}
|
||||
|
||||
function cp_closesoon() {
|
||||
// Close the table a split-second from now.
|
||||
cp_closePID = window.setTimeout('cp_close()', 250);
|
||||
cp_closePid = setTimeout(cp_close, 250);
|
||||
}
|
||||
|
||||
function cp_cancelclose() {
|
||||
// Don't close the colour table after all.
|
||||
if (cp_closePID)
|
||||
window.clearTimeout(cp_closePID);
|
||||
if (cp_closePid) {
|
||||
clearTimeout(cp_closePid);
|
||||
}
|
||||
}
|
||||
|
||||
function cp_onclick() {
|
||||
function cp_onclick(e) {
|
||||
// Clicked on a colour.
|
||||
// Close the table, set the colour, fire an onchange event.
|
||||
cp_caller.style.backgroundColor = '#' + this.label;
|
||||
var input = document.getElementById(cp_caller.label)
|
||||
input.value = this.label;
|
||||
var element = e.target;
|
||||
var colour;
|
||||
// Walk up the DOM, looking for a colour.
|
||||
while (element) {
|
||||
colour = element.cp_colour;
|
||||
if (colour !== undefined) {
|
||||
break;
|
||||
}
|
||||
element = element.parentNode;
|
||||
}
|
||||
if (colour !== undefined) {
|
||||
// Set the colour.
|
||||
cp_activeSwatch.cp_input.value = colour;
|
||||
cp_updateSwatch(cp_activeSwatch);
|
||||
// Fire a change event.
|
||||
var evt = document.createEvent('HTMLEvents');
|
||||
evt.initEvent('change', false, true);
|
||||
cp_activeSwatch.cp_input.dispatchEvent(evt);
|
||||
}
|
||||
// Close the table.
|
||||
cp_close();
|
||||
if (input.onchange) {
|
||||
input.onchange();
|
||||
}
|
||||
}
|
||||
|
||||
function cp_onmouseover() {
|
||||
// Place a black border on the cell if the contents are light,
|
||||
// a white border if the contents are dark.
|
||||
this.style.borderStyle = 'dotted';
|
||||
var rgb = cp_hex2rgb(this.label);
|
||||
if (rgb[0] + rgb[1] + rgb[2] > 255 * 3 / 2)
|
||||
this.style.borderColor = 'black';
|
||||
else
|
||||
this.style.borderColor = 'white';
|
||||
}
|
||||
|
||||
function cp_onmouseout() {
|
||||
// Remove the border.
|
||||
if (this.label == cp_defaultcolour) {
|
||||
this.style.borderStyle = 'outset';
|
||||
} else {
|
||||
this.style.border = 'solid 2px #' + this.label;
|
||||
}
|
||||
}
|
||||
|
||||
function cp_hex2rgb(hexcode) {
|
||||
// Parse '0088ff' and return the [r, g, b] ints.
|
||||
var m =
|
||||
hexcode.match(/^([a-f0-9][a-f0-9])([a-f0-9][a-f0-9])([a-f0-9][a-f0-9])$/);
|
||||
if (m) {
|
||||
var r = parseInt(m[1], 16);
|
||||
var g = parseInt(m[2], 16);
|
||||
var b = parseInt(m[3], 16);
|
||||
return [r, g, b];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -563,13 +563,12 @@ td.taboff:hover {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#colourpicker {
|
||||
z-index: 999;
|
||||
.cp_swatch {
|
||||
vertical-align: middle !important;
|
||||
}
|
||||
|
||||
#colourpicker>table {
|
||||
border-collapse: separate;
|
||||
z-index: 999;
|
||||
#cp_popup {
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.shadowBlock>.blocklyPath {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<script src="app_controller.js"></script>
|
||||
<script src="/storage.js"></script>
|
||||
<link rel="stylesheet" href="factory.css">
|
||||
<link rel="stylesheet" href="cp.css">
|
||||
<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>
|
||||
<script>
|
||||
var blocklyFactory;
|
||||
|
||||
@@ -494,11 +494,11 @@ WorkspaceFactoryController.prototype.reinjectPreview = function(tree) {
|
||||
* Changes the name and colour of the selected category.
|
||||
* Return if selected element is a separator.
|
||||
* @param {string} name New name for selected category.
|
||||
* @param {string} colour New colour for selected category.
|
||||
* Must be a valid CSS string.
|
||||
* @param {?string} colour New colour for selected category, or null if none.
|
||||
* Must be a valid CSS string, or '' for none.
|
||||
*/
|
||||
WorkspaceFactoryController.prototype.changeSelectedCategory =
|
||||
function(name, colour) {
|
||||
WorkspaceFactoryController.prototype.changeSelectedCategory = function(name,
|
||||
colour) {
|
||||
var selected = this.model.getSelected();
|
||||
// Return if a category is not selected.
|
||||
if (selected.type != ListElement.TYPE_CATEGORY) {
|
||||
|
||||
@@ -61,15 +61,18 @@ WorkspaceFactoryInit.initWorkspaceFactory = function(controller) {
|
||||
* @private
|
||||
*/
|
||||
WorkspaceFactoryInit.initColourPicker_ = function(controller) {
|
||||
// Array of Blockly category colours, consistent with the 15 degree default
|
||||
// of the block factory's colour wheel.
|
||||
var colours = [];
|
||||
var row = [];
|
||||
for (var hue = 0; hue < 360; hue += 15) {
|
||||
row.push(Blockly.hueToHex(hue).substring(1));
|
||||
if (row.length == 6) {
|
||||
colours.push(row);
|
||||
row = [];
|
||||
// Array of Blockly category colours, consistent with the colour defaults.
|
||||
var colours = [
|
||||
[20, 65, 120],
|
||||
[160, 210, 230],
|
||||
[260, 290, '']
|
||||
];
|
||||
// Convert hue numbers to RRGGBB strings.
|
||||
for (var y = 0; y < colours.length; y++) {
|
||||
for (var x = 0; x < colours[y].length; x++) {
|
||||
if (colours[y][x] !== '') {
|
||||
colours[y][x] = Blockly.hueToHex(colours[y][x]).substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Override the default colours.
|
||||
@@ -242,7 +245,7 @@ WorkspaceFactoryInit.assignWorkspaceFactoryClickHandlers_ =
|
||||
}
|
||||
document.getElementById('categoryName').value = selected.name;
|
||||
document.getElementById('categoryColour').value = selected.color ?
|
||||
selected.color.substring(1).toLowerCase() : '000000';
|
||||
selected.color.substring(1).toLowerCase() : '';
|
||||
// Link the colour picker to the field.
|
||||
cp_init('categoryColour');
|
||||
blocklyFactory.openModal('dropdownDiv_editCategory');
|
||||
@@ -252,7 +255,8 @@ WorkspaceFactoryInit.assignWorkspaceFactoryClickHandlers_ =
|
||||
('click',
|
||||
function() {
|
||||
var name = document.getElementById('categoryName').value.trim();
|
||||
var colour = '#' + document.getElementById('categoryColour').value;
|
||||
var colour = document.getElementById('categoryColour').value;
|
||||
colour = colour ? '#' + colour : null;
|
||||
controller.changeSelectedCategory(name, colour);
|
||||
blocklyFactory.closeModal();
|
||||
});
|
||||
|
||||
@@ -535,7 +535,8 @@ ListElement.prototype.changeName = function (name) {
|
||||
/**
|
||||
* Sets the color of a category. If tries to set the color of something other
|
||||
* than a category, returns.
|
||||
* @param {string} color The color that should be used for that category.
|
||||
* @param {?string} color The color that should be used for that category,
|
||||
* or null if none.
|
||||
*/
|
||||
ListElement.prototype.changeColor = function (color) {
|
||||
if (this.type != ListElement.TYPE_CATEGORY) {
|
||||
|
||||
@@ -221,14 +221,20 @@ WorkspaceFactoryView.prototype.moveTabToIndex =
|
||||
* Given a category ID and color, use that color to color the left border of the
|
||||
* tab for that category.
|
||||
* @param {string} id The ID of the category to color.
|
||||
* @param {string} color The color for to be used for the border of the tab.
|
||||
* Must be a valid CSS string.
|
||||
* @param {?string} colour The colour for to be used for the border of the tab,
|
||||
* or null if none. Must be a valid CSS string.
|
||||
*/
|
||||
WorkspaceFactoryView.prototype.setBorderColor = function(id, color) {
|
||||
var tab = this.tabMap[id];
|
||||
tab.style.borderLeftWidth = '8px';
|
||||
tab.style.borderLeftStyle = 'solid';
|
||||
tab.style.borderColor = color;
|
||||
WorkspaceFactoryView.prototype.setBorderColor = function(id, colour) {
|
||||
var style = this.tabMap[id].style;
|
||||
if (colour) {
|
||||
style.borderLeftWidth = '8px';
|
||||
style.borderLeftStyle = 'solid';
|
||||
style.borderColor = colour;
|
||||
} else {
|
||||
style.borderLeftWidth = '';
|
||||
style.borderLeftStyle = '';
|
||||
style.borderColor = '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user