Skip to content

Commit 5d11af8

Browse files
authored
Merge 43f37dc into 9400343
2 parents 9400343 + 43f37dc commit 5d11af8

File tree

7 files changed

+108
-23
lines changed

7 files changed

+108
-23
lines changed

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ namespace CefSharp
8686
}
8787
}
8888
}
89+
90+
_jsBindingPropertyName = extraInfo->GetString("JsBindingPropertyName");
91+
_jsBindingPropertyNameCamelCase = extraInfo->GetString("JsBindingPropertyNameCamelCase");
8992
}
9093

9194
void CefAppUnmanagedWrapper::OnBrowserDestroyed(CefRefPtr<CefBrowser> browser)
@@ -123,13 +126,6 @@ namespace CefSharp
123126
auto global = context->GetGlobal();
124127
auto browserWrapper = FindBrowserWrapper(browser->GetIdentifier());
125128

126-
auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
127-
global->SetValue("CefSharp", cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
128-
129-
//We'll support both CefSharp and cefSharp, for those who prefer the JS style
130-
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
131-
global->SetValue("cefSharp", cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
132-
133129
//TODO: JSB: Split functions into their own classes
134130
//Browser wrapper is only used for BindObjectAsync
135131
auto bindObjAsyncFunction = CefV8Value::CreateFunction(kBindObjectAsync, new BindObjectAsyncHandler(_registerBoundObjectRegistry, _javascriptObjects, browserWrapper));
@@ -138,11 +134,21 @@ namespace CefSharp
138134
auto isObjectCachedFunction = CefV8Value::CreateFunction(kIsObjectCached, new RegisterBoundObjectHandler(_javascriptObjects));
139135
auto postMessageFunction = CefV8Value::CreateFunction(kPostMessage, new JavascriptPostMessageHandler(rootObject == nullptr ? nullptr : rootObject->CallbackRegistry));
140136

141-
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
142-
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
143-
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
144-
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
145-
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
137+
if (!_jsBindingPropertyName.empty())
138+
{
139+
auto cefSharpObj = CefV8Value::CreateObject(NULL, NULL);
140+
global->SetValue(_jsBindingPropertyName, cefSharpObj, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
141+
142+
cefSharpObj->SetValue(kBindObjectAsync, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
143+
cefSharpObj->SetValue(kDeleteBoundObject, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
144+
cefSharpObj->SetValue(kRemoveObjectFromCache, removeObjectFromCacheFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
145+
cefSharpObj->SetValue(kIsObjectCached, isObjectCachedFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
146+
cefSharpObj->SetValue(kPostMessage, postMessageFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
147+
}
148+
149+
//We'll support both CefSharp and cefSharp, for those who prefer the JS style
150+
auto cefSharpObjCamelCase = CefV8Value::CreateObject(NULL, NULL);
151+
global->SetValue(_jsBindingPropertyNameCamelCase, cefSharpObjCamelCase, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_READONLY);
146152

147153
cefSharpObjCamelCase->SetValue(kBindObjectAsyncCamelCase, bindObjAsyncFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);
148154
cefSharpObjCamelCase->SetValue(kDeleteBoundObjectCamelCase, unBindObjFunction, CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_NONE);

CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ namespace CefSharp
2828
bool _focusedNodeChangedEnabled;
2929
bool _legacyBindingEnabled;
3030

31+
// The property names used to call binded objects
32+
CefString _jsBindingPropertyName;
33+
CefString _jsBindingPropertyNameCamelCase;
34+
3135
// The serialized registered object data waiting to be used.
3236
gcroot<Dictionary<String^, JavascriptObject^>^> _javascriptObjects;
3337

CefSharp.Core/ManagedCefBrowserAdapter.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void ManagedCefBrowserAdapter::CreateBrowser(IWindowInfo^ windowInfo, BrowserSet
4848

4949
legacyBindingEnabled = objectRepository->HasBoundObjects;
5050

51-
//For legacy binding we only add values if we have bond objects
51+
//For legacy binding we only add values if we have bond objects.
5252
if (legacyBindingEnabled)
5353
{
5454
auto listValue = CefListValue::Create();
@@ -61,6 +61,23 @@ void ManagedCefBrowserAdapter::CreateBrowser(IWindowInfo^ windowInfo, BrowserSet
6161

6262
extraInfo->SetBool("LegacyBindingEnabled", legacyBindingEnabled);
6363

64+
// Retrieve the configurable binding property names, throw exception if empty or illegal characters
65+
auto jsBindingPropertyName = _javaScriptObjectRepository->WindowPropertyName;
66+
if (!StringCheck::EnsureLettersAndNumbers(jsBindingPropertyName))
67+
{
68+
throw gcnew InvalidOperationException("CefBrowserHost::CreateBrowser invalid or illegal characters used for binding property names. Alphanumeric and underscores characters only.");
69+
}
70+
71+
if (StringCheck::IsFirstCharacterLowercase(jsBindingPropertyName))
72+
{
73+
extraInfo->SetString("JsBindingPropertyNameCamelCase", StringUtils::ToNative(jsBindingPropertyName));
74+
}
75+
else
76+
{
77+
extraInfo->SetString("JsBindingPropertyName", StringUtils::ToNative(jsBindingPropertyName));
78+
extraInfo->SetString("JsBindingPropertyNameCamelCase", StringUtils::ToNative(_javaScriptObjectRepository->ConvertToCamelCase(jsBindingPropertyName)));
79+
}
80+
6481
if (!CefBrowserHost::CreateBrowser(*cefWindowInfoWrapper->GetWindowInfo(), _clientAdapter.get(), addressNative,
6582
*browserSettings->_browserSettings, extraInfo, static_cast<CefRefPtr<CefRequestContext>>(requestContext)))
6683
{

CefSharp/CefSharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
<Compile Include="Internals\CookieManagerDecorator.cs" />
113113
<Compile Include="Internals\ParentProcessMonitor.cs" />
114114
<Compile Include="Internals\HeaderNameValueCollection.cs" />
115+
<Compile Include="Internals\StringCheck.cs" />
115116
<Compile Include="Internals\TaskScheduler\LimitedConcurrencyLevelTaskScheduler.cs" />
116117
<Compile Include="IUrlRequest.cs" />
117118
<Compile Include="IUrlRequestClient.cs" />

CefSharp/IJavascriptObjectRepository.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace CefSharp
1313
/// </summary>
1414
public interface IJavascriptObjectRepository : IDisposable
1515
{
16+
string WindowPropertyName { get; set; }
1617
/// <summary>
1718
/// Register an object for binding in Javascript. You can either
1819
/// register an object in advance or as part of the <see cref="ResolveObject"/>

CefSharp/Internals/JavascriptObjectRepository.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ public class JavascriptObjectRepository : IJavascriptObjectRepository
5252
/// </summary>
5353
public bool IsBrowserInitialized { get; set; }
5454

55+
public string WindowPropertyName { get; set; }
56+
57+
public JavascriptObjectRepository()
58+
{
59+
WindowPropertyName = "CefSharp";
60+
}
61+
5562
public void Dispose()
5663
{
5764
ResolveObject = null;
@@ -404,6 +411,8 @@ internal bool TrySetProperty(long objectId, string name, object value, out strin
404411
/// <param name="camelCaseJavascriptNames">camel case the javascript names of properties/methods</param>
405412
private void AnalyseObjectForBinding(JavascriptObject obj, bool analyseMethods, bool analyseProperties, bool readPropertyValue, bool camelCaseJavascriptNames)
406413
{
414+
var isWindowPropertyFirstCharacterLowercase = StringCheck.IsFirstCharacterLowercase(WindowPropertyName);
415+
407416
if (obj.Value == null)
408417
{
409418
return;
@@ -425,7 +434,7 @@ private void AnalyseObjectForBinding(JavascriptObject obj, bool analyseMethods,
425434
continue;
426435
}
427436

428-
var jsMethod = CreateJavaScriptMethod(methodInfo, camelCaseJavascriptNames);
437+
var jsMethod = CreateJavaScriptMethod(methodInfo, camelCaseJavascriptNames, isWindowPropertyFirstCharacterLowercase);
429438
obj.Methods.Add(jsMethod);
430439
}
431440
}
@@ -444,12 +453,12 @@ private void AnalyseObjectForBinding(JavascriptObject obj, bool analyseMethods,
444453
continue;
445454
}
446455

447-
var jsProperty = CreateJavaScriptProperty(propertyInfo, camelCaseJavascriptNames);
456+
var jsProperty = CreateJavaScriptProperty(propertyInfo, camelCaseJavascriptNames, isWindowPropertyFirstCharacterLowercase);
448457
if (jsProperty.IsComplexType)
449458
{
450459
var jsObject = CreateJavascriptObject(camelCaseJavascriptNames, rootObject: false);
451460
jsObject.Name = propertyInfo.Name;
452-
jsObject.JavascriptName = GetJavascriptName(propertyInfo.Name, camelCaseJavascriptNames);
461+
jsObject.JavascriptName = GetJavascriptName(propertyInfo.Name, camelCaseJavascriptNames, isWindowPropertyFirstCharacterLowercase);
453462
jsObject.Value = jsProperty.GetValue(obj.Value);
454463
jsProperty.JsObject = jsObject;
455464

@@ -469,12 +478,12 @@ private void RaiseResolveObjectEvent(string name)
469478
ResolveObject?.Invoke(this, new JavascriptBindingEventArgs(this, name));
470479
}
471480

472-
private static JavascriptMethod CreateJavaScriptMethod(MethodInfo methodInfo, bool camelCaseJavascriptNames)
481+
private static JavascriptMethod CreateJavaScriptMethod(MethodInfo methodInfo, bool camelCaseJavascriptNames, bool isWindowPropertyCamelCase)
473482
{
474483
var jsMethod = new JavascriptMethod();
475484

476485
jsMethod.ManagedName = methodInfo.Name;
477-
jsMethod.JavascriptName = GetJavascriptName(methodInfo.Name, camelCaseJavascriptNames);
486+
jsMethod.JavascriptName = GetJavascriptName(methodInfo.Name, camelCaseJavascriptNames, isWindowPropertyCamelCase);
478487
jsMethod.Function = methodInfo.Invoke;
479488
jsMethod.ParameterCount = methodInfo.GetParameters().Length;
480489
jsMethod.Parameters = methodInfo.GetParameters()
@@ -489,12 +498,12 @@ private static JavascriptMethod CreateJavaScriptMethod(MethodInfo methodInfo, bo
489498
return jsMethod;
490499
}
491500

492-
private static JavascriptProperty CreateJavaScriptProperty(PropertyInfo propertyInfo, bool camelCaseJavascriptNames)
501+
private static JavascriptProperty CreateJavaScriptProperty(PropertyInfo propertyInfo, bool camelCaseJavascriptNames, bool isWindowPropertyCamelCase)
493502
{
494503
var jsProperty = new JavascriptProperty();
495504

496505
jsProperty.ManagedName = propertyInfo.Name;
497-
jsProperty.JavascriptName = GetJavascriptName(propertyInfo.Name, camelCaseJavascriptNames);
506+
jsProperty.JavascriptName = GetJavascriptName(propertyInfo.Name, camelCaseJavascriptNames, isWindowPropertyCamelCase);
498507
jsProperty.SetValue = (o, v) => propertyInfo.SetValue(o, v, null);
499508
jsProperty.GetValue = (o) => propertyInfo.GetValue(o, null);
500509

@@ -533,13 +542,21 @@ private static bool IsComplexType(Type type)
533542
return !baseType.IsPrimitive && baseType != typeof(string);
534543
}
535544

536-
private static string GetJavascriptName(string str, bool camelCaseJavascriptNames)
545+
private static string GetJavascriptName(string str, bool camelCaseJavascriptNames, bool isWindowPropertyCamelCase)
537546
{
538-
if (!camelCaseJavascriptNames)
547+
if (!isWindowPropertyCamelCase)
539548
{
540-
return str;
549+
if (!camelCaseJavascriptNames)
550+
{
551+
return str;
552+
}
541553
}
542554

555+
return ConvertToCamelCase(str);
556+
}
557+
558+
public static string ConvertToCamelCase(string str)
559+
{
543560
if (string.IsNullOrEmpty(str))
544561
{
545562
return string.Empty;

CefSharp/Internals/StringCheck.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright © 2020 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
using System.Text.RegularExpressions;
6+
7+
namespace CefSharp.Internals
8+
{
9+
public static class StringCheck
10+
{
11+
/// <summary>
12+
/// Regex check to ensure string contains only letters, numbers and underscores.
13+
/// </summary>
14+
/// <param name="stringToCheck"></param>
15+
/// <returns></returns>
16+
public static bool EnsureLettersAndNumbers(string stringToCheck)
17+
{
18+
if (!string.IsNullOrWhiteSpace(stringToCheck))
19+
{
20+
return Regex.IsMatch(stringToCheck, @"^\w+$");
21+
}
22+
23+
return false;
24+
}
25+
26+
public static bool IsFirstCharacterLowercase(string str)
27+
{
28+
if (!string.IsNullOrEmpty(str))
29+
{
30+
if (char.IsLetter(str[0]))
31+
{
32+
return char.IsLower(str[0]);
33+
}
34+
}
35+
36+
return false;
37+
}
38+
}
39+
}

0 commit comments

Comments
 (0)