Related
I want to convert a time string to Arabic. For example I want to convert 10:00 PM to مساءاً ١٠:٠٠. I am using format function with locale.
import ar from 'date-fns/locale/ar-SA'
...
str = format(date, 'h:mm a', {locale: ar})
But it gives a string like this 10:00 م. Basically digits are not getting translated.
You can try with this logic
const mappedDigit = (char: string): string => {
switch (char) {
case '0':
return '٠';
case '1':
return '١';
case '2':
return '٢';
case '3':
return '٣';
case '4':
return '٤';
case '5':
return '٥';
case '6':
return '٦';
case '7':
return '٧';
case '8':
return '٨';
case '9':
return '٩';
default:
return char;
}
};
const getArabicFormats = (englishString: string): string => {
let newArabicString = '';
for (let i = 0; i < englishString.length; i += 1) {
newArabicString += mappedDigit(englishString[i]);
}
newArabicString = newArabicString.replace('AM', 'ص');
newArabicString = newArabicString.replace('PM', 'م');
return newArabicString;
};
In a Google spreadsheet doc, I need to set the cell colour based in duplicated value in column with different colours for each duplicated values. The colour should be set to 'random' so that all of them will be different.
After the condition is applied the colour of the cells should look this: https://docs.google.com/spreadsheets/d/1YuUjg_PqD53AoTrxgvnEHYwZ_disqvNKDMmp5dRYq4I/edit?usp=sharing
This question is similar to this How to highlight cell if value duplicate in same column for google spreadsheet? but not the same since I need to give different colours for each duplicated value
I guess I might need a script to get this done? I don't think this could be done with 'conditional formatting' rule feature.
UPDATE:
The conditionals posted by Player0 works great. But the problem is that in the example I just posted a few cells. In the real spreadsheet I have hundreds of values which change from time to time. Then with this approach I will need to create a lot of condicional rules. I need to do this dynamically with a single formula. It should be a single formula/script to be applied to Column A which generate a random color for each value coincidence...
yellow:
=(ARRAYFORMULA(VLOOKUP(A1; {UNIQUE(A$1:A)\
ROW(INDIRECT("A1:A"&COUNTUNIQUE(A$1:A)+1))}; 2; 0))=1)*
(COUNTIF(A:A; A1)>1)
blue:
=(ARRAYFORMULA(VLOOKUP(A1; {UNIQUE(A$1:A)\
ROW(INDIRECT("A1:A"&COUNTUNIQUE(A$1:A)+1))}; 2; 0))=2)*
(COUNTIF(A:A; A1)>1)
pink:
=(ARRAYFORMULA(VLOOKUP(A1; {UNIQUE(A$1:A)\
ROW(INDIRECT("A1:A"&COUNTUNIQUE(A$1:A)+1))}; 2; 0))=3)*
(COUNTIF(A:A; A1)>1)
green:
=(ARRAYFORMULA(VLOOKUP(A1; {UNIQUE(A$1:A)\
ROW(INDIRECT("A1:A"&COUNTUNIQUE(A$1:A)+1))}; 2; 0))=4)*
(COUNTIF(A:A; A1)>1)
red:
=(ARRAYFORMULA(VLOOKUP(A1; {UNIQUE(A$1:A)\
ROW(INDIRECT("A1:A"&COUNTUNIQUE(A$1:A)+1))}; 2; 0))=5)*
(COUNTIF(A:A; A1)>1)
orange:
=(ARRAYFORMULA(VLOOKUP(A1; {UNIQUE(A$1:A)\
ROW(INDIRECT("A1:A"&COUNTUNIQUE(A$1:A)+1))}; 2; 0))=6)*
(COUNTIF(A:A; A1)>1)
Here is a script that works:
function colorDuplicates() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow();
var column = 1
ss.getRange(2, column, lr).setBackground(null);
var color = ["#EA9999","#F9CB9C","#FFE599","#B6D7A8","#A2C4C9","#9FC5E8","#B4A7D6","#D5A6BD","#CCCCCC","#B45F06","#666666","#FF0000","#FF9900","#FFFF00","#00FF00","#00FFFF"];
var c = 0;
var checkcolor = false;
for (var i = 2; i < lr+1;i++){
if (checkcolor == true) {
c++;
checkcolor = false;
}
var a = ss.getRange(i, column).getValue();
if (a == "") {continue;}
var cellcolor = ss.getRange(i, column).getBackground();
if (cellcolor != "#ffffff") {continue;}
for (var j = i+1;j< lr+1;j++){
var b = ss.getRange(j, column).getValue();
if (a != b) {continue;}
var cellcolor = ss.getRange(j, column).getBackground();
if (cellcolor != "#ffffff") {continue;}
ss.getRange(i, column).setBackground(color[c]);
ss.getRange(j, column).setBackground(color[c]);
checkcolor = true;
}
}
}
function colorDuplicates2() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = getLastRowSpecial(ss.getRange("A:A").getValues());
var lc = ss.getLastColumn();
ss.getRange(2, 1, lr).setBackground(null);
ss.insertColumnAfter(lc);
ss.getRange(1, lc+1).setFormula("=FILTER(UNIQUE(A2:A);UNIQUE(A2:A)<>\"\")"); // Change the ";" for a "," if you are in the us
var numValues = getLastRowSpecial(ss.getRange(1, lc+1, lr).getValues());
var values = new Array(36);
for (var a = 1;a<numValues+1;a++){
values[a] = String(ss.getRange(a, lc+1).getValue());
}
var color = ["#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff", "#4a86e8", "#0000ff", "#9900ff", "#ff00ff", "#e6b8af", "#f4cccc", "#fce5cd", "#ea9999", "#f9cb9c", "#ffe599", "#b6d7a8", "#a2c4c9", "#a4c2f4", "#9fc5e8", "#b4a7d6", "#d5a6bd", "#cc4125", "#e06666", "#f6b26b", "#ffd966", "#93c47d", "#76a5af", "#6d9eeb", "#6fa8dc", "#8e7cc3", "#c27ba0", "#a61c00", "#cc0000", "#e69138", "#f1c232", "#6aa84f", "#45818e", "#3c78d8", "#3d85c6", "#674ea7", "#a64d79", "#85200c", "#990000"];
for (var i = 2;i<lr+1;i++){
switch (String(ss.getRange(i, 1).getValue())) {
case values[1]:
ss.getRange(i, 1).setBackground(color[1]);
break;
case values[2]:
ss.getRange(i, 1).setBackground(color[2]);
break;
case values[3]:
ss.getRange(i, 1).setBackground(color[3]);
break;
case values[4]:
ss.getRange(i, 1).setBackground(color[4]);
break;
case values[5]:
ss.getRange(i, 1).setBackground(color[5]);
break;
case values[6]:
ss.getRange(i, 1).setBackground(color[6]);
break;
case values[7]:
ss.getRange(i, 1).setBackground(color[7]);
break;
case values[8]:
ss.getRange(i, 1).setBackground(color[8]);
break;
case values[9]:
ss.getRange(i, 1).setBackground(color[9]);
break;
case values[10]:
ss.getRange(i, 1).setBackground(color[10]);
break;
case values[11]:
ss.getRange(i, 1).setBackground(color[11]);
break;
case values[12]:
ss.getRange(i, 1).setBackground(color[12]);
break;
case values[13]:
ss.getRange(i, 1).setBackground(color[13]);
break;
case values[14]:
ss.getRange(i, 1).setBackground(color[14]);
break;
case values[15]:
ss.getRange(i, 1).setBackground(color[15]);
break;
case values[16]:
ss.getRange(i, 1).setBackground(color[16]);
break;
case values[17]:
ss.getRange(i, 1).setBackground(color[17]);
break;
case values[18]:
ss.getRange(i, 1).setBackground(color[18]);
break;
case values[19]:
ss.getRange(i, 1).setBackground(color[19]);
break;
case values[20]:
ss.getRange(i, 1).setBackground(color[20]);
break;
case values[21]:
ss.getRange(i, 1).setBackground(color[21]);
break;
case values[22]:
ss.getRange(i, 1).setBackground(color[22]);
break;
case values[23]:
ss.getRange(i, 1).setBackground(color[23]);
break;
case values[24]:
ss.getRange(i, 1).setBackground(color[24]);
break;
case values[25]:
ss.getRange(i, 1).setBackground(color[25]);
break;
case values[26]:
ss.getRange(i, 1).setBackground(color[26]);
break;
case values[27]:
ss.getRange(i, 1).setBackground(color[27]);
break;
case values[28]:
ss.getRange(i, 1).setBackground(color[28]);
break;
case values[29]:
ss.getRange(i, 1).setBackground(color[29]);
break;
case values[30]:
ss.getRange(i, 1).setBackground(color[30]);
break;
case values[31]:
ss.getRange(i, 1).setBackground(color[31]);
break;
case values[32]:
ss.getRange(i, 1).setBackground(color[32]);
break;
case values[33]:
ss.getRange(i, 1).setBackground(color[33]);
break;
case values[34]:
ss.getRange(i, 1).setBackground(color[34]);
break;
case values[35]:
ss.getRange(i, 1).setBackground(color[35]);
break;
case values[36]:
ss.getRange(i, 1).setBackground(color[36]);
break;
}
}
ss.deleteColumn(lc+1);
}
function getLastRowSpecial(range){
var rowNum = 0;
var blank = false;
for(var row = 0; row < range.length; row++){
if(range[row][0] === "" && !blank){
rowNum = row;
blank = true;
}else if(range[row][0] !== ""){
blank = false;
};
};
return rowNum;
}
It has only 16 colors, and it will leave blank the duplicates that finds after that, but you can add as many more colors as you need.
It works for finding duplicates in column A, but you can also change that if you need it to be another column.
Try it and feel free to ask me anything. Good luck!
*I edited my previous answer beacuse it didnt take in to account values that appeard more than twice.
*I edited again to avoid empty cells.
You can use a script function to take advantage of a hashing algorithm like md5 and obtain an (almost) unique byte string for any cell value.
Selecting the first 3 bytes and adding a leading "#", you can convert such a hash into a hex color.
After that, looping over the range values to determine the color codes and setting the background is all that is required.
/**
* Return an md5 hash as hex string.
* #example md5("lorem ipsum") => "80a751fde577028640c419000e33eba6"
*/
function md5(txt) {
return Utilities.computeDigest(
Utilities.DigestAlgorithm.MD5,
txt
).map(
c => (255 & c).toString(16).padStart(2, '0')
).join(
""
);
}
/**
* Return a hex color from any string.
* #example txt2color("lorem ipsum") => "#80a751"
*/
function txt2color(txt) {
return "#" + md5(txt).slice(0, 6);
}
/**
* Set the background color of the cells in the active
* range so that the cells with same value get the
* same background color
*/
function highlight_same_values() {
const range = SpreadsheetApp.getActiveRange();
const bgcolors = range.getValues().map(
row => row.map(
cell => cell ? txt2color(cell) : null
)
);
range.setBackgrounds(bgcolors);
}
I have a TIFF file. I want to slice it automatically (specifying the number of slices in horizontal and vertical) and save them into TIFF files (I don't want to change the format to png or ...)
I know that in photoshop you can choose the slice tool>>right click>>Divide Slice>>Save for web
However, the "Save for web" doesn't offer saving in TIFF Format and also I don't think it can work for large file (which is the case here).
Anything that can help (script, plugin) is welcome
With the help of some online codes, I created the script below which is capable of automatically slicing a big TIFF into smaller Tiff files:
#target photoshop
function main(){
if(!documents.length) return;
var dlg=
"dialog{text:'Script Interface',bounds:[100,100,380,290],"+
"panel0:Panel{bounds:[10,10,270,180] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"title:StaticText{bounds:[60,10,220,40] , text:'File Chop' ,properties:{scrolling:undefined,multiline:undefined}},"+
"panel1:Panel{bounds:[10,40,250,130] , text:'' ,properties:{borderStyle:'etched',su1PanelCoordinates:true},"+
"statictext1:StaticText{bounds:[10,10,111,30] , text:'Accross' ,properties:{scrolling:undefined,multiline:undefined}},"+
"statictext2:StaticText{bounds:[140,10,230,27] , text:'Down' ,properties:{scrolling:undefined,multiline:undefined}},"+
"across:DropDownList{bounds:[10,30,100,50]},"+
"down:DropDownList{bounds:[140,30,230,50]},"+
"saveFiles:Checkbox{bounds:[10,60,230,80] , text:'Save and Close new files?'}},"+
"button0:Button{bounds:[10,140,110,160] , text:'Ok' },"+
"button1:Button{bounds:[150,140,250,160] , text:'Cancel' }}};"
var win = new Window(dlg,'File Chop');
if(version.substr(0,version.indexOf('.'))>9){
win.panel0.title.graphics.font = ScriptUI.newFont("Georgia","BOLD",20);
g = win.graphics;
var myBrush = g.newBrush(g.BrushType.SOLID_COLOR, [1.00, 1.00, 1.00, 1]);
g.backgroundColor = myBrush;
var myPen =g.newPen (g.PenType.SOLID_COLOR, [1.00, 0.00, 0.00, 1],lineWidth=1);
}
win.center();
for(var i=1;i<31;i++){
win.panel0.panel1.across.add ('item', i);
win.panel0.panel1.down.add ('item', i);
}
win.panel0.panel1.across.selection=0;
win.panel0.panel1.down.selection=0;
var done = false;
while (!done) {
var x = win.show();
if (x == 0 || x == 2) {
win.canceled = true;
done = true;
} else if (x == 1) {
done = true;
{
if(!documents.length)return;
var startRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PIXELS;
doc = app.activeDocument;
app.displayDialogs = DialogModes.NO;
doc.flatten();
var tilesAcross = parseInt(win.panel0.panel1.across.selection.index)+1;
var tilesDown =parseInt(win.panel0.panel1.down.selection.index)+1;
var tileWidth = parseInt(doc.width/tilesAcross);
var tileHeight = parseInt(doc.height/tilesDown);
var SaveFiles = win.panel0.panel1.saveFiles.value;
ProcessFiles(tilesDown,tilesAcross,tileWidth,tileHeight,SaveFiles);
app.preferences.rulerUnits = startRulerUnits;
}
}
}
}
main();
function ProcessFiles(Down,Across,offsetX,offsetY,SaveFiles){
try{
var newName = activeDocument.name.match(/(.*)\.[^\.]+$/)[1];
}catch(e){var newName="UntitledChop"}
var Path='';
try{
Path = activeDocument.path;
}catch(e){Path = "~/Desktop";}
if(SaveFiles){
Path = Folder(decodeURI(Path) +"/FileChop");
if(!Path.exists) Path.create();
}
TLX = 0; TLY = 0; TRX = offsetX; TRY = 0;
BRX = offsetX; BRY = offsetY; BLX = 0; BLY = offsetY;
for(var a = 0; a < Down; a++){
for(var i = 0;i <Across; i++){
var NewFileName = newName +"#"+a+"-"+i;
app.activeDocument.duplicate (NewFileName, true);
activeDocument.selection.select([[TLX,TLY],[TRX,TRY],[BRX,BRY],[BLX,BLY]], SelectionType.REPLACE, 0, false);
executeAction( charIDToTypeID( "Crop" ), undefined, DialogModes.NO );
app.activeDocument.selection.deselect();
if(SaveFiles){
var saveFile = File(decodeURI(Path+"/"+NewFileName+".tiff"));
SaveTIFF(saveFile);
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
}
activeDocument = documents[0];
TLX = offsetX * (i+1) ; TRX = TLX + offsetX; BRX = TRX; BLX = TLX;
}
TLX = 0; TLY = offsetY * (a +1); TRX = offsetX; TRY = offsetY * (a +1);
BRX = offsetX; BRY = TRY + offsetY; BLX = 0; BLY = (offsetY * (a +1)+offsetY);
}
if(SaveFiles){
Path.execute()
}
}
function SaveTIFF(saveFile){
tiffSaveOptions = new TiffSaveOptions();
tiffSaveOptions.embedColorProfile = true;
tiffSaveOptions.alphaChannels = true;
tiffSaveOptions.layers = true;
tiffSaveOptions.imageCompression = TIFFEncoding.NONE;
activeDocument.saveAs(saveFile, tiffSaveOptions, true, Extension.LOWERCASE);
}
In my Razor view I have the following code to layout the page. However based on the media query I want to change the value of numberOfColumns. So that when MD I use 2 and when SM I use 1 - ie. Change how many columns I output based on the media query. Is this possible?
If not is there another way to do this?
bool inRow = false;
int numberOfColumns = 3; //<---- Change based on media query
int columnNumber = 0;
foreach (OzCpCruiseListItem cruiseItem in Model.CruisesBrief)
{
columnNumber++;
if (columnNumber == 1)
{
inRow = true;
}
if (inRow && columnNumber == 1)
{
#Html.Raw("<!-- START Row --><br />")
#Html.Raw("<div class=\"row\">")
}
<div class="col-lg-4 col-md-6 col-sm-12"> //<--- 3 col for large, 2 for medium, 1 small
</div>
if (columnNumber == numberOfColumns)
{
inRow = false;
#Html.Raw("</div>")
#Html.Raw("<!-- END Row --><br />")
columnNumber = 0;
}
}
//Close row if needed
if (inRow)
{
#Html.Raw("<!-- END AT END Row --><br />")
#Html.Raw("</div")
}
Thanks to #DavidG who tried to understand what I was on about. Below is my solution to what I was trying to ask for. Stated another way: "I never wanted the columns in the row to wrap to the next line when in a particular media query."
The only way I can come up to do this is to output some HTML per media query and vary the classes (for the columns) based on the number of columns I am expecting via:
result += $"<div class=\"col-{aMediaValue.ToLower()}-{columnSize}\">";
If there is a better way I would like to hear it as I don't like the fact I am outputting 4 lots of HTML for the same data - 1 for each media query.
#functions {
HtmlString CardViewOutput(string aMediaValue)
{
string result = "";
int columnCount;
switch (aMediaValue.Trim().ToUpper())
{
case "LG":
columnCount = 3;
break;
case "MD":
columnCount = 2;
break;
case "SM":
case "XS":
columnCount = 1;
break;
default:
columnCount = 1;
break;
}
int columnSize = 12 / columnCount;
bool inRow = false;
int columnNumber = 0;
foreach (OzCpCruiseListItem cruiseItem in Model.CruisesBrief)
{
columnNumber++;
if (columnNumber == 1)
{
inRow = true;
}
if (inRow && columnNumber == 1)
{
result += "<!-- START Row --><br />";
result += "<div class=\"row\">";
}
result += $"<div class=\"col-{aMediaValue.ToLower()}-{columnSize}\">";
result += "</div>";
if (columnNumber == columnCount)
{
inRow = false;
result += "</div>";
result += "<!-- END Row --><br />";
columnNumber = 0;
}
}
//Close row if needed
if (inRow)
{
result += "<!-- END AT END Row --><br />";
result += "</div>";
}
return new HtmlString(result);
}
}
#*-- Card View -----------------------------------------------------------------------------------------------------------*#
#if (Model.CruisesBrief.Count == 0)
{
#Html.Raw("<div class=\"row\"><div class=\"col-lg-12 col-md-12 col-sm-12 col-xs-12\">No cruises to display.</div></div>")
}
else
{
#Html.Raw("<div class=\"visible-lg\">")
#Html.Raw("LARGE")
#Html.Raw(CardViewOutput("LG"))
#Html.Raw("</div>")
#Html.Raw("<div class=\"visible-md\">")
#Html.Raw("MEDIUM")
#Html.Raw(CardViewOutput("MD"))
#Html.Raw("</div>")
#Html.Raw("<div class=\"visible-sm\">")
#Html.Raw("SMALL")
#Html.Raw(CardViewOutput("SM"))
#Html.Raw("</div>")
#Html.Raw("<div class=\"visible-xs\">")
#Html.Raw("EXTRA SMALL")
#Html.Raw(CardViewOutput("XS"))
#Html.Raw("</div>")
}
#*-- /Card View ----------------------------------------------------------------------------------------------------------*#
I've made an autocomplete that work very well in the swf file.
very simple, when the user write the first letter, a suggestion is made with words.
I've published my project for IOS.
When I'm trying it on the Iphone, nothing is suggested when I'm typing the first letter.
I have to write the first letter and then clicked on "enter" in order to display the suggestions...
I don't want the users to "validate" in order to have the suggestion but simply by typing a letter.
Do you know what could be the problem ? Anyone can help me ?
Weirdly, I've tried on an Android device, and it's working perfectly well ! (like my swf).
Here is my code :
urlLoader.load(new URLRequest("test.txt"));
urlLoader.addEventListener(Event.COMPLETE, loadComplete);
inputField.addEventListener(KeyboardEvent.KEY_UP, suggest);
function loadComplete(e:Event):void
{
suggestions = e.target.data.split(",");
}
function suggest(e:KeyboardEvent):void
{
suggested = [];
for (var i:int = 0; i < textfields.length; i++)
{
removeChild(textfields[i]);
}
textfields = [];
for (var j:int = 0; j < suggestions.length; j++)
{
if (suggestions[j].indexOf(inputField.text.toLowerCase()) == 0)
{
var term:TextField = new TextField();
term.width = 300;
term.height = 20;
term.x = 70;
term.y = (20 * suggested.length) + 314;
term.border = true;
term.borderColor = 0x353535;
term.background = true;
term.backgroundColor = 0xFF9900;
term.textColor = 0x4C311D;
term.defaultTextFormat = format;
term.addEventListener(MouseEvent.MOUSE_UP, useWord);
term.addEventListener(MouseEvent.MOUSE_OVER, hover);
term.addEventListener(MouseEvent.MOUSE_OUT, out);
term.addEventListener(MouseEvent.CLICK, tellMe);
addChild(term);
textfields.push(term);
suggested.push(suggestions[j]);
term.text = suggestions[j];
}
}
if (inputField.length == 0)
{
suggested = [];
for (var k:int = 0; k < textfields.length; k++)
{
removeChild(textfields[k]);
}
textfields = [];
}
if(e.keyCode == Keyboard.DOWN && currentSelection < textfields.length-1)
{
currentSelection++;
textfields[currentSelection].textColor = 0x4C311D;
}
if(e.keyCode == Keyboard.UP && currentSelection > 0)
{
currentSelection--;
textfields[currentSelection].textColor = 0x4C311D;
}
if(e.keyCode == Keyboard.ENTER)
{
inputField.text = textfields[currentSelection].text;
suggested = [];
for (var l:int = 0; l < textfields.length; l++)
{
removeChild(textfields[l]);
}
textfields = [];
currentSelection = 0;
}
}
function useWord(e:MouseEvent):void
{
inputField.text = e.target.text;
suggested = [];
for (var i:int = 0; i < textfields.length; i++)
{
removeChild(textfields[i]);
}
textfields = [];
}
Thank you
EDIT
Here's my new code with Stagetext
var myTextField:StageText = new StageText();
var stageTextInitOptions:StageTextInitOptions;
var urlLoader:URLLoader = new URLLoader();
var suggestions:Array = new Array();
var suggested:Array = new Array();
var textfields:Array = new Array();
var format:TextFormat = new TextFormat();
var currentSelection:int = -1;
var searchChannel:SoundChannel = new SoundChannel();
myTextField.returnKeyLabel = ReturnKeyLabel.SEARCH;
myTextField.addEventListener(KeyboardEvent.KEY_UP, suggest);
stageTextInitOptions = new StageTextInitOptions(false);
myTextField = new StageText(stageTextInitOptions);
myTextField.softKeyboardType = SoftKeyboardType.DEFAULT;
myTextField.returnKeyLabel = ReturnKeyLabel.DONE;
myTextField.autoCorrect = true;
myTextField.fontSize = 20;
myTextField.color = 0x000000;
myTextField.fontWeight = "bold";
myTextField.stage = this.stage;
myTextField.viewPort = new Rectangle(25, 108, stage.stageWidth-40, 28);
urlLoader.load(new URLRequest("Sports2.txt"));
urlLoader.addEventListener(Event.COMPLETE, loadComplete);
myTextField.addEventListener(KeyboardEvent.KEY_UP, suggest);
KeyboardEvent.KEY_UP, KeyboardEvent.KEY_DOWN, TextEvent.TEXT_INPUT doesn't really works at iOS. KeyboardEvent.KEY_DOWN is dispatching only on some keys. I saw only key "Enter".