Categories
discuss

Counting the byte size of a file encoded in ISO 8859-7 in JavaScript

Background

I am writing an esoteric language called Jolf. It is used on the lovely site codegolf SE. If you don’t already know, a lot of challenges are scored in bytes. People have made lots of languages that utilize either their own encoding or a pre-existing encoding.

On the interpreter for my language, I have a byte counter. As you might expect, it counts the number of bytes in the code. Until now, I’ve been using a UTF-8 en/decoder (utf8.js). I am now using the ISO 8859-7 encoding, which has Greek characters. Nor does the text upload actually work. I need to count the actually bytes contained within an uploaded file. Also, is there a way to read the contents of said encoded file?

Question

Given a file encoded in ISO 8859-7 obtained from an <input> element on the page, is there any way to obtain the number of bytes contained in that file? And, given “plaintext” (i.e. text put directly into a <textarea>), how might I count the bytes in that as if it was encoded in ISO 8859-7?

What I’ve tried

The input element is called isogreek. The file resides in the <input> element. The content is ΦX族, a Greek character, a latin character (each of which should be a byte) and a Chinese character, which should be more than one byte (?).

isogreek.files[0].size;      // is 3; should be more.

var reader = new FileReader();
reader.readAsBinaryString(isogreek.files[0]);      // corrupts the string to `ÖX?`
reader.readAsText(isogreek.files[0]);              // �X?
reader.readAsText(isogreek.files[0],"ISO 8859-7"); // �X?

Answer

Extended from this comment.

As @pvg mentioned in the comments, the string resulting from readAsBinaryString would be correct, but is corrupted for two reasons:

A. The result is encoded in ISO-8859-1. You can use a function to fix this:

function convertFrom1to7(text) {
  // charset is the set of chars in the ISO-8859-7 encoding from 0xA0 and up, encoded with this format:
  // - If the character is in the same position as in ISO-8859-1/Unicode, use a "!".
  // - If the character is a Greek char with 720 subtracted from its char code, use a ".".
  // - Otherwise, use uXXXX format.
  var charset = "!u2018u2019!u20ACu20AF!!!!.!!!!u2015!!!!...!...!.!....................!............................................!";
  var newtext = "", newchar = "";
  for (var i = 0; i < text.length; i++) {
    var char = text[i];
    newchar = char;
    if (char.charCodeAt(0) >= 160) {
      newchar = charset[char.charCodeAt(0) - 160];
      if (newchar === "!") newchar = char;
      if (newchar === ".") newchar = String.fromCharCode(char.charCodeAt(0) + 720);
    }
    newtext += newchar;
  }
  return newtext;
} 

B. The Chinese character isn’t a part of the ISO-8859-7 charset (because the charset supports up to 256 unique chars, as the table shows). If you want to include arbitrary Unicode characters in a program, you will probably need to do one of these two things:

  1. Count the bytes of that program in i.e. UTF-8 or UTF-16. This can be done pretty easily with the library you linked. However, if you want this to be done automatically, you’ll need a function that checks if the content of the textarea is a valid ISO-8859-7 file, like this:
function isValidISO_8859_7(text) {
  var charset = /[u0000-u00A0u2018u2019u00A3u20ACu20AFu00A6-u00A9u037Au00AB-u00ADu2015u00B0-u00B3u0384-u0386u00B7u0388-u038Au00BBu038Cu00BDu038E-u03CE]/;
  var valid = true;
  for (var i = 0; i < text.length; i++) {
    valid = valid && charset.test(text[i]);
  }
  return valid;
}
  1. Create your own, custom variant of ISO-8859-7 that uses a specific byte (or more than one) to signify that the next 2 or 3 bytes belong to a single Unicode char. This can be pretty much as simple or complex as you like, from one char signifying a 2-byte char and one signifying a 3-byter to everything between 80 and 9F setting up for the next few. Here’s a basic example that uses 80 as the 2-byter and 81 as the 3-byter (assumes the text is encoded in ISO-8859-1):
function reUnicode(text) {
  var newtext = "";
  for (var i = 0; i < text.length; i++) {
    if (text.charCodeAt(i) === 0x80) {
      newtext += String.fromCharCode((text.charCodeAt(++i) << 8) + text.charCodeAt(++i));
    } else if (text.charCodeAt(i) === 0x81) {
      var charcode = (text.charCodeAt(++i) << 16) + (text.charCodeAt(++i) << 8) + text.charCodeAt(++i) - 65536;
      newtext += String.fromCharCode(0xD800 + (charcode >> 10), 0xDC00 + (charcode & 1023)); // Convert into a UTF-16 surrogate pair
    } else {
      newtext += convertFrom1to7(text[i]);
    }
  }
  return newtext;
}

I can go into either method in more detail if you desire.

Categories
discuss

Polymer elements within angular 2 component

I have a set of custom polymer elements, that I would like to use within an angular 2 application.

It seems like there’s a problem concerning the content tag of the polymer element. The content of the element gets rendered at the wrong place within the polymer element, if the element is located within an angular 2 component.

Example:

The template of my polymer element “my-button” looks like this:

<template>

  <button>
    <content></content>
  </button>

</template>

Use outside angular

When I use this element outside of my angular 2 component, I get the result that I expected:

Use:

<my-button>Foo</my-button>

Result:

<my-button>
  <button>
    Foo
  </button>
<my-button>

Use within angular 2 component

When used within an angular 2 component, the content always gets rendered at the end of the elements template. Just like the content tag didn’t exist.

Use:

<my-button>Foo</my-button>

Result:

<my-button>
  <button>

  </button>
  "Foo"
<my-button>

Question

The problem might be, that polymer and angular 2 both use the content tag for transclution. So maybe things get a little messy when using both together.

I would love to use all of my polymer elements inside angular 2. So any ideas on how to fix this would be very much appreciated.

Answer

There are a few open issue about Angular2 combined with Polymer. For example Angular doesn’t use Polymer.dom(el)... for manipulating a Polymer elements children. This is probably what breaks your components. A workaround is to enable full shadow DOM and polyfills. See https://www.polymer-project.org/1.0/docs/devguide/settings.html

An issue I haven’t found a solution yet is passing <template>s (like required for example for <iron-list>. Angular handles templates on its own and doesn’t pass it to the Polymer element.

There is a ngNonBindable directive. I haven’t tried it yet on the <template ngNonBindable> myself but it might work. I tried it seems that’s only to ignore [prop]="field"/prop="{{field}} bindings.

Another issue is with <style is="custom-style">. They can only be added in the <head> element or within Polymer elements, but not to Angular components.

See also Two-way binding in Angular 2 with NgModel and mutating bound property?

Categories
discuss

Angular 2 Generate Class Name Based on ngFor Index

I’m running into a problem with creating a dynamic class name based on the Angular 2 ngFor loop index. I had to use the following syntax because Angular 2 does not like ngFor and ngIf on the same element.

With this syntax, how can I create a dynamic class name with the value of index at {{index}}. I know this isn’t proper A2 code, but I put it in my code example to show you where I would like the value to appear.

<div class="product-detail__variants">
    <template ngFor #variant [ngForOf]="variants" #index="index">
        <div *ngIf="currentVariant == index">
            <div class="product-detail-carousel-{{index}}">

            </div>
        </div>
    </template>
</div>

The value “variants” is an empty array of a set length. “variant” thus has no value.

“currentVariant” is a number that by default equals 0.

EDIT: This code above is correct. I had another extraneous error that I thought was connected to this code.

Answer

I don’t really understand your problem 😉

There are two ways to set classes for a specific element:

  • The way you do with curly brackets:

    @Component({
      selector: 'my-app',
      template: `
        <div class="product-detail__variants">
          <template ngFor #variant [ngForOf]="variants" #index="index">
            <div *ngIf="currentVariant == index">
              <div class="product-detail-carousel-{{index}}">
                Test
              </div>
            </div>
          </template>
        </div>
      `,
      styles: [
        '.product-detail-carousel-2 { color: red }'
      ]
    })
    

    Test is displayed only for the third element (index 2) and in red.

  • As suggested by @Langley using the ngClass directive

    import {NgClass} from 'angular2/common';
    
    @Component({
      selector: 'my-app',
      template: `
        <div class="product-detail__variants">
          <template ngFor #variant [ngForOf]="variants" #index="index">
            <div *ngIf="currentVariant == index">
              <div class="product-detail-carousel-{{index}}">
                Test
              </div>
            </div>
          </template>
        </div>
      `,
      styles: [
        '.product-detail-carousel-2 { color: red }'
      ],
      directives: [ NgClass ]
    })
    

    The different is that you need to specify the NgClass directive within the providers attribute of your component. Again Test is displayed only for the third element (index 2) and in red.

Your following sentences: “The value variants is an empty array of a set length. variant thus has no value. currentVariant is a number that by default equals 0.”. How do you expect something to be displayed if your array is empty. An ngFor is an iteration…

Hope it helps you, Thierry

Categories
discuss

Failed to execute query selector on document, id is not a valid selector

I’m trying to create a way to edit a bunch of comments and identify them by some id that I can generate. The errors I’m having is that there is:

SyntaxError: Failed to execute ‘querySelector’ on ‘Document’: ‘#1234’ is not a valid selector. However, I don’t see how this is possible since I clearly have id=1234 in the <p>.

Additionally, there are issues where when I comment everything else and do an alert(id), this does not work for the second form and the error is that:

TypeError: Cannot read property ‘classList’ of null.

Here is it in jfiddle: https://jsfiddle.net/wafqgq0L/2/

document.querySelector('.editable').addEventListener('click', function(event) {
 var index = event.target.id.indexOf('_');

 var id = event.target.id.substring(0,index);
	
	//actual data
	document.querySelector('#'+id).classList.add('hidden');
  
  //edit button
  document.querySelector("#"+id+"_edit").classList.add('hidden');
  
  //textarea
	document.querySelector("#"+id+"_editable").classList.remove('hidden');
  
  //save button
	document.querySelector("#"+id+"_save").classList.remove('hidden');

});
.hidden {
  display: none;
}
//all id will be like 12345_comment

<div class="editable">
<p id="1234">
  Some comment
</p>

<form action="form.php" method="post">
  <textarea id="1234_editable" class="hidden">Some comment</textarea>
  <a href="#" id="1234_edit">Edit</a>
  <a href="#" id="1234_save" class="hidden">Save</a>
</form>
</div>
<br><br>
<div class="editable">
<p id="123">
  Some comment
</p>

<form class="editable" action="form.php" method="post">
  <textarea id="123_editable" class="hidden">Some comment</textarea>
  <a href="#" id="123_edit">Edit</a>
  <a href="#" id="123_save" class="hidden">Save</a>
</form>
</div>

Answer

You might find jQuery easier, and it’s automatically cross-browser (and faster to type!) Since it’s tagged on your question, here is the jQuery solution:

Edit: The tag jQuery was removed from the original question on May 25 ’19 at 21:10 (3 years after question was asked and answered), by user John, with the inexplicable editor comment “remove spam tags”.

jsFiddle Demo

$('[id^=edit_]').click(function(){
    var id = this.id.split('_')[1];
    $('#'+id).addClass('hidden');
    $('#edit_'+id).addClass('hidden');

    $('#save_'+id).removeClass('hidden');  
    $('#editable_'+id).removeClass('hidden');  
});

$('[id^=save_]').click(function(){
    var id = this.id.split('_')[1];
    $('#'+id).removeClass('hidden');
    $('#edit_'+id).removeClass('hidden');

    $('#save_'+id).addClass('hidden');  
    $('#editable_'+id).addClass('hidden');  
});

Note that I switched around the id_number and the idName_ prefix. This makes it much easier to target those elements using the starts with selector: id^=

Categories
discuss

Testing Doze feature (Android 6.0 Marshmallow) in Genymotion

I’ve tried the commands from Google

adb shell dumpsys battery unplug
adb shell dumpsys deviceidle step

on both “PREVIEW – Google Nexus 6P – 6.0.0 – API 23 – 1440×2560” and “PREVIEW – Google Nexus 5X – 6.0.0 – API 23 – 1080×1920” virtual devices from Genymotion but unfortunately cannot put anyone to idle mode. Always after second command I see Stepped to: ACTIVE.

Then trying

adb shell dumpsys deviceidle force-idle

I see Unable to go idle; not enabled. This is strange because Genymotion states in release note (https://www.genymotion.com/#!/release-notes) for version 2.6.0, which I use, that “Doze now works properly.”

Is there anyone who managed to use and test Doze in Genymotion? Should I use some other commands?

Answer

I’m part of the Genymotion team.

The release note is not correct and our patch for Doze feature has not been released on the preview. Sorry for this mistake.

We will soon release Marshmallow officially and it will include Doze feature. On this future release you will need to enable Doze manually, at each device startup, by running the following command:

adb shell dumpsys deviceidle enable

Then, all the usual commands will work perfectly:

adb shell dumpsys battery unplug
adb shell dumpsys deviceidle step

UPDATE: The release has been done, Doze is available now on Genymotion devices.

Source: stackoverflow
Text is available under the Creative Commons Attribution-ShareAlike License; additional terms may apply. By using this site, you agree to the Privacy Policy, and Copyright Policy. Content is available under CC BY-SA 3.0 unless otherwise noted. The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 © No Copyrights, All Questions are retrived from public domain..