Binding a regular expression as an observable in knockoutjs - javascript

I'm new to KnockoutJS. I know how to define an observable that will be used to change the text of an element (or be updated from a text element), however, I want the data in my model to be actually a regular expression with read/write access. I want to set it using a textarea like:
<textarea data-bind="value: regex"></textarea>
And show it on the page using:
<span data-bind="text: regex"></span>
Now the initialization is working:
//inside the model
this.regex = ko.observable( /,/g );
And both the textarea and span get updated (because the native regular expression variable has a toString() function that works perfectly well showing a string representation of the regular expression). But when I change the regex in the textarea the span doesn't update. It seems like setting the observable is failing.
This is understandable because the value from textarea is just a text and in order to convert it to an actual regular expression, some code is needed. I have the code. Let's call it function str2regex() with a body similar to this:
//this is pseudo code and doesn't neccesarily work
function str2regex( str )
var r = str.match( "^\/(.+?)\/([mig])*$" );
if ( r ) {
if ( r[2] === null ) {
return new RegExp( r[1] );
} else {
return new RegExp( r[1], r[2] );
}
}
return null;
}
How can I set the value of type regular expression in my model using the text that is coming from the textarea?

You should transform your str2regex to computed observable like this:
// str2regex transformed to computed observable
self.regex = ko.computed(function(){
var m = self.regex_string().match(/^\/(.+)\/([mig])*$/);
return m ? new RegExp(m[1], m[2]) : null;
});
But you still should track your regex string editable in textarea (regex_string observable in my code).
Take a look: http://jsbin.com/ofehuj/2/edit

Related

AngularJS bind and replace text [duplicate]

I'm new to AngularJS and trying to create a simple app that will allow me to upload files to my Laravel driven website. I want the form to show me the preview of what the uploaded item will look like. So I am using ng-model to achieve this and I have stumbled upon the following:
I have an input with some basic bootstrap stylings and I am using custom brackets for AngularJS templating (because as I mentioned, I am using Laravel with its blading system). And I need to remove spaces from the input (as I type it) and replace them with dashes:
<div class="form-group"><input type="text" plaeholder="Title" name="title" class="form-control" ng-model="gnTitle" /></div>
And then I have this:
<a ng-href="/art/[[gnTitle | spaceless]]" target="_blank">[[gnTitle | lowercase]]</a>
And my app.js looks like this:
var app = angular.module('neoperdition',[]);
app.config(function($interpolateProvider){
$interpolateProvider.startSymbol('[[').endSymbol(']]');
});
app.filter('spaceless',function(){
return function(input){
input.replace(' ','-');
}
});
I get the following error:
TypeError: Cannot read property 'replace' of undefined
I understand that I need to define the value before I filter it, but I'm not sure where to define it exactly. And also, if I define it, I don't want it to change my placeholder.
There are few things missing in your filter. First of all you need to return new string. Secondary, regular expression is not correct, you should use global modifier in order to replace all space characters. Finally you also need to check if the string is defined, because initially model value can be undefined, so .replace on undefined will throw error.
All together:
app.filter('spaceless',function() {
return function(input) {
if (input) {
return input.replace(/\s+/g, '-');
}
}
});
Demo: http://plnkr.co/edit/5Rd1SLjvNI18MDpSEP0a?p=preview
Bravi just try this filter
for eaxample {{X | replaceSpaceToDash}}
app.filter('replaceSpaceToDash', function(){
var replaceSpaceToDash= function( input ){
var words = input.split( ' ' );
for ( var i = 0, len = words.length; i < len; i++ )
words[i] = words[i].charAt( 0 ) + words[i].slice( 1 );
return words.join( '-' );
};
return replaceSpaceToDash;
});
First, you have to inject your filter in you module by adding it's name to the array :
var app = angular.module('neoperdition',['spaceless']);
Secondly, the function of the filter have to return something. The String.prototype.replace() return a new String. so you have to return it :
app.filter('spaceless',function(){
return function(input){
return input.replace(' ','-');
}
});
Edit: dfsq's answer being a lot more accurate than mine.

.replace() expression not being updated within computed observable

I have created within knockoutJS a computed observable that supports user input as well as performs text manipulation on the input.
This observable is bound to input field and label. The intent is to allow a user to enter a new name but I want to prevent the user from using non-alphanumeric characters. The function works both in bindings and evaluation of the string, but the replace function does not seem to update. The substring function works (limiting the text to 255 characters) but I think I have something not set exactly right in the replace. Int eh current funciton, if an illegal character is entered the user receives the toastr alert but the replace function does not replace the character with white space. I'd appreciate any suggestions.
html
<label class="reportNameTextBox" title="Click to edit report name" data-bind="text: NameFormatted() == null || NameFormatted().trim().length == 0 ? '[ Click To Enter Name ]' : NameFormatted(), css: { 'noData': NameFormatted() == null || NameFormatted().trim().length == 0 }"></label>
<input class="editInput" type="text" data-bind="value: NameFormatted" />
knockout
report.NameFormatted = ko.computed({
read: function () {
return report.Name().substring(0, 255);
},
write: function (value) {
var insertedText = value;
var Exp = /^[a-zA-Z0-9]*$/i;
if (!insertedText.match(Exp)) {
DisplayWarning('Attention', 'Non-alphanumeric may not be used.');
return report.Name(insertedText.substring(0, 255)).replace(/[^a-zA-Z 0-9]+/g, ''); ;
}
else {
DisplayWarning('Success', 'yeah');
return report.Name(insertedText.substring(0, 255));
}
},
owner: this
});
I believe your problem lies on this line:
return report.Name(insertedText.substring(0, 255)).replace(/[^a-zA-Z 0-9]+/g, '');
You're chaining the replace method to the wrong object (report.Name instead of substring)
return report.Name(insertedText.substring(0, 255).replace(/[^a-zA-Z 0-9]+/g, ''));
Just move the replace method inside the bracket and it should work as expected.

How to get first text node of a string while containing bold and italic tags?

String(s) is dynamic
It is originated from onclick event when user clicks anywhere in dom
if string(s)'s first part that is:
"login<b>user</b>account"
is enclosed in some element like this :
"<div>login<b>user</b>account</div>",
then I can get it with this:
alert($(s).find('*').andSelf().not('b,i').not(':empty').first().html());
// result is : login<b>user</b>account
But how can i get the same result in this condition when it is not enclosed in any element .i.e. when it is not enclosed in any element?
I tried this below code which works fine when first part do not include any <b></b> but it only gives "login" when it does include these tags.
var s = $.trim('login<b>user</b> account<tbody> <tr> <td class="translated">Lorem ipsum dummy text</td></tr><tr><td class="translated">This is a new paragraph</td></tr><tr><td class="translated"><b>Email</b></td></tr><tr><td><i>This is yet another text</i></td> </tr></tbody>');
if(s.substring(0, s.indexOf('<')) != ''){
alert(s.substring(0, s.indexOf('<')));
}
Note:
Suggest a generic solution that is not specific for this above string only. It should work for both the cases when there is bold tags and when there ain't any.
So it's just a b or a i, heh?
A recursive function is always the way to go. And this time, it's probably the best way to go.
var s = function getEm(elem) {
var ret = ''
// TextNode? Great!
if (elem.nodeType === 3) {
ret += elem.nodeValue;
}
else if (elem.nodeType === 1 &&
(elem.nodeName === 'B' || elem.nodeName === 'I')) {
// Element? And it's a B or an I? Get his kids!
ret += getEm(elem.firstChild);
}
// Ain't nobody got time fo' empty stuff.
if (elem.nextSibling) {
ret += getEm(elem.nextSibling);
}
return ret;
}(elem);
Jsfiddle demonstrating this: http://jsfiddle.net/Ralt/TZKsP/
PS: Parsing HTML with regex or custom tokenizer is bad and shouldn't be done.
You're trying to retrieve all of the text up to the first element that's not a <b> or <i>, but this text could be wrapped in an element itself. This is SUPER tricky. I feel like there's a better way to implement whatever it is you're trying to accomplish, but here's a solution that works.
function initialText(s){
var test = s.match(/(<.+?>)?.*?<(?!(b|\/|i))/);
var match = test[0];
var prefixed_element = test[1];
// if the string was prefixed with an element tag
// remove it (ie '<div> blah blah blah')
if(prefixed_element) match = match.slice(prefixed_element.length);
// remove the matching < and return the string
return match.slice(0,-1);
}
You're lucky I found this problem interesting and challenging because, again, this is ridiculous.
You're welcome ;-)
Try this:
if (s.substring(0, s.indexOf('<')) != '') {
alert(s.substring(0, s.indexOf('<tbody>')));
}

Dojo Toolkit: how to escape an HTML string?

A user of my HTML 5 application can enter his name in a form, and this name will be displayed elsewhere. More specifically, it will become the innerHTML of some HTML element.
The problem is that this can be exploited if one enters valid HTML markup in the form, i.e. some sort of HTML injection, if you will.
The user's name is only stored and displayed on the client side so in the end the user himself is the only one who is affected, but it's still sloppy.
Is there a way to escape a string before I put it in an elements innerHTML in Dojo? I guess that Dojo at one point did in fact have such a function (dojo.string.escape()) but it doesn't exist in version 1.7.
Thanks.
dojox.html.entities.encode(myString);
Dojo has the module dojox/html/entities for HTML escaping. Unfortunately, the official documentation still provides only pre-1.7, non-AMD example.
Here is an example how to use that module with AMD:
var str = "<strong>some text</strong>"
require(['dojox/html/entities'], function(entities) {
var escaped = entities.encode(str)
console.log(escaped)
})
Output:
<strong>some text</strong>
As of Dojo 1.10, the escape function is still part of the string module.
http://dojotoolkit.org/api/?qs=1.10/dojo/string
Here's how you can use it as a simple template system.
require([
'dojo/string'
], function(
string
){
var template = '<h1>${title}</h1>';
var message = {title: 'Hello World!<script>alert("Doing something naughty here...")</script>'}
var html = string.substitute(
template
, message
, string.escape
);
});
I tried to find out how other libraries implement this function and I stole the idea of the following from MooTools:
var property = (document.createElement('div').textContent == null) ? 'innerText': 'textContent';
elem[property] = "<" + "script" + ">" + "alert('a');" + "</" + "script" + ">";
So according to MooTools there is either the innerText or the textContent property which can escape HTML.
Check this example of dojo.replace:
require(["dojo/_base/lang"], function(lang){
function safeReplace(tmpl, dict){
// convert dict to a function, if needed
var fn = lang.isFunction(dict) ? dict : function(_, name){
return lang.getObject(name, false, dict);
};
// perform the substitution
return lang.replace(tmpl, function(_, name){
if(name.charAt(0) == '!'){
// no escaping
return fn(_, name.slice(1));
}
// escape
return fn(_, name).
replace(/&/g, "&").
replace(/</g, "<").
replace(/>/g, ">").
replace(/"/g, """);
});
}
// that is how we use it:
var output = safeReplace("<div>{0}</div",
["<script>alert('Let\' break stuff!');</script>"]
);
});
Source: http://dojotoolkit.org/reference-guide/1.7/dojo/replace.html#escaping-substitutions

Translate user selected text with Google Translate API (and jQuery)

I am working on some JavaScript for a website with content in multiple languages. I would like to use the Google Translate API to allow the user to select a word (or phrase) and have a translation automatically provided. For the time being, I'm simply having it alert the result for testing.
This is what I have so far:
google.load("language", "1");
function getSelection() {
var selection = (!!document.getSelection) ? document.getSelection() :
(!!window.getSelection) ? window.getSelection() :
document.selection.createRange().text;
if (selection.text)
selection = selection.text
console.log(selection);
return selection
}
$(document).ready(function() {
$(window).mouseup(function() {
var selection = getSelection();
if (selection != "") {
google.language.translate(selection, "", "en", function(result) {
if (!result.error) {
alert(result.translation);
} else {
alert(result.error);
}
});
}
});
});
The problem that I'm running into is that my getSelection() function is returning a Range objects, which is apparently incompatible with google's language.translate() function. All I really need is a way to retrieve the actual text from the Range as a string so I can pass that. As far as I know there's some really easy, obvious way to do this that I'm just missing (yes, I tried using selection.text), but my experience with JavaScript is limited and Googling it hasn't revealed anything useful.
Can anyone help?
Try jQuery google translate - http://code.google.com/p/jquery-translate/.
Unsurprisingly there was a really obvious answer that I just completely missed. selection.toString()...
You can do something like this:
function getSelection() {
var selection = window.getSelection ? window.getSelection() + ''
: document.selection.createRange().text;
return selection
}
By concatenating an empty string to the result of the getSelection() method, its value gets converted to string, it's a common short-hand, equivalent to call the toString method, because:
var test = {
toString: function () {
return 'foo';
}
};
test+'' == 'foo'; // true
You also don't need to use the double logical negation (!!) in a ternary, because the first operand, the condition, its automatically converted to Boolean.

Categories

Resources