I've created a project in flutter that uses a webview widget. I also tried the webviewx widget to fix the error I got in the project. but I am still getting the same error. The loader is running while the page is loading and the loader is closing after the page is loaded.
There is a back button on the website. When this button is clicked, the "javascript:history.back()" code is running. On iOS devices, the loader starts and does not close. On android it works normally. I leave the code used below. thank you for your help.
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webviewx/webviewx.dart';
import 'package:onesignal_flutter/onesignal_flutter.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
void main() {
runApp(Eren());
OneSignal.shared.setAppId("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
// The promptForPushNotificationsWithUserResponse function will show the iOS or Android push notification prompt. We recommend removing the following code and instead using an In-App Message to prompt for notification permission
OneSignal.shared.promptUserForPushNotificationPermission().then((accepted) {
print("Accepted permission: $accepted");
});
}
bool isLoading = true;
String adres='';
Timer? timer;
int _start = 10;
class Eren extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: SafeArea(child: webViewWidget()),
),
);
}
}
_launchURL(String url) async {
if (url.startsWith('tel:')) {
launchUrl(
Uri.parse(url),
mode: LaunchMode.platformDefault,
);
}
if (url.startsWith('https')) {
launchUrl(
Uri.parse(url.toString()),
mode: LaunchMode.externalApplication,
);
}
if (url.startsWith('http')) {
launchUrl(
Uri.parse(url.toString()),
mode: LaunchMode.externalApplication,
);
}
}
class webViewWidget extends StatefulWidget {
const webViewWidget({Key? key}) : super(key: key);
#override
State<webViewWidget> createState() => _webViewWidgetState();
}
class _webViewWidgetState extends State<webViewWidget> {
#override
Widget build(BuildContext context) {
return Stack(
children: [
WebViewX(
width: double.infinity,
height: double.infinity,
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
onPageStarted: (start) {
setState(() {
isLoading = true;
});
},
javascriptMode: JavascriptMode.unrestricted,
initialContent: 'https://www.etcxxx.com',
navigationDelegate: (NavigationRequest request) {
adres=request.content.sourceType.toString();
print("tür:"+request.content.sourceType.toString());
if (request.content.source
.startsWith("https://www.etcxxx.com") ||
request.content.source.startsWith("https://etcxxx.com") ||
request.content.source
.startsWith("http://www.etcxxx.com") ||
request.content.source.startsWith("http://etcxxx.com")) {
print('dahili link');
return NavigationDecision.navigate;
} else {
print('harici link');
_launchURL(request.content.source);
return NavigationDecision.prevent;
}
},
),
isLoading
? Container(
decoration:
BoxDecoration(color: Colors.grey.shade200.withOpacity(0.7)),
child: Center(
child: CircularProgressIndicator(
color: Colors.deepOrangeAccent,
strokeWidth: 5,
),
),
)
: Stack(),
],
);
}
}
flutter webview loader error
Related
I am trying to develop a simple plugin for CKEditor 5. My ultimate goal is to have the plugin emit the following HTML:
<div class="icms_note">
<div class="span-6 module-note">
<p>User can edit here</p>
</div>
<div class="clear"></div>
</div>
I was having issues with the user editable area being in the wrong spot so I reduced the output to just this:
<div class="icms_note">
<p>User can edit here</p>
</div>
and the data model looks like this:
<icms_note>
<paragraph>User can edit here</paragraph>
</icms_note>
So I can get the data model created correctly and the HTML ends up in the editor the way I expect but I can't edit the text in the paragraph. I click on the text and the cursor just jumps out. I've tried looking at other examples and the tutorials but I can't seem to get it to work right. My plugin code is below. Any help would be appreciated.
note.js
import Plugin from "#ckeditor/ckeditor5-core/src/plugin";
import NoteEditing from "./noteediting";
import NoteUI from "./noteui";
export default class Note extends Plugin {
static get requires() {
return [ NoteEditing, NoteUI ];
}
static get pluginName() {
return "IcmsNote";
}
}
noteui.js
import Plugin from "#ckeditor/ckeditor5-core/src/plugin";
import { ButtonView } from "#ckeditor/ckeditor5-ui";
export default class NoteUI extends Plugin {
init() {
const editor = this.editor;
editor.ui.componentFactory.add( "icms_note", (locale) => {
const button = new ButtonView(locale);
button.set({
label: "Note",
withText: true,
tooltip: true
});
button.on( "execute", () => {
editor.execute("insertNote");
});
return button;
} );
}
}
noteediting.js
import Position from "#ckeditor/ckeditor5-engine/src/view/position";
import NoteCommand from "./notecommand";
export default class NoteEditing extends Plugin {
init() {
this._defineSchema();
this._defineConverters();
this.editor.commands.add("insertNote", new NoteCommand(this.editor));
}
_defineSchema() {
const schema = this.editor.model.schema;
schema.register( "icms_note", {
inheritAllFrom: "$text",
allowIn: [ "$root", "$container" ],
isInline: true
});
}
_defineConverters() {
const conversion = this.editor.conversion;
conversion.for( "downcast" ).elementToElement({
model: "icms_note",
view: ( modelElementValue, conversionApi ) => {
const { writer } = conversionApi;
const outerDivElement = writer.createEditableElement("div", {class: "icms_note"});
return outerDivElement;
}
});//<div><div class=\"span-6 module-note\"><p>Enter note</p></div><div class=\"clear\"></div></div>
conversion.for( "upcast" ).elementToElement({
view: {
name: "div",
attributes: {
classes: [ "icms_note" ]
}
},
model: {
key: "icms_note",
value: viewElement => {
const val = viewElement.getChildren()[0].getChildren()[0].data;
return val;
}
}
});
}
}
notecommand.js
import Command from "#ckeditor/ckeditor5-core/src/command";
export default class NoteCommand extends Command {
constructor(editor) {
super(editor);
}
execute() {
console.log("NoteCommand#execute");
const model = this.editor.model;
const selection = model.document.selection;
model.change( modelWriter => {
let position = selection.getFirstPosition();
const icmsNote = modelWriter.createElement("icms_note");
const paragraph = modelWriter.createElement("paragraph");
modelWriter.insert(paragraph, icmsNote);
modelWriter.insertText("User can edit here", paragraph);
let positionElementName = position.parent.name;
while (positionElementName != "$root" && positionElementName != "$container") {
position = model.createPositionAfter(position.parent);
positionElementName = position.parent.name;
}
model.insertContent(icmsNote, position, null, {
setSelection: "after"
});
});
}
}
I have a modal component and I'm writing the story for it. It looks something like this:
import { Story, Meta } from '#storybook/html';
export default {
title: 'Components/Modal',
argTypes: {
open: {
name: 'Opened',
control: 'boolean'
},
},
args: {
open: false,
}
} as Meta;
const Template: Story = (args) => {
return `
<my-modal open="${args.open}">
Some example content inside the modal
</my-modal>
`;
};
export const Modal: Story = Template.bind({});
I have the arg open on the controls and I can change its value to true and the modal shows. But I would like the story to have a button and when it's clicked, the modal shows.
I can't find a way to do this in the current version of Storybook for web components.
I've seen there are some hooks available for React (import { useArgs } from '#storybook/api';) that allows you to change the arguments value dynamically but I can't see how to do this for web components?
Any helps will be highly appreciated.
Just add that button to the template:
import { Story, Meta } from '#storybook/html';
export default {
title: 'Components/Modal',
argTypes: {
open: {
name: 'Opened',
control: 'boolean'
},
},
args: {
open: false,
}
} as Meta;
const Template: Story = (args) => {
return `
<button
type="button"
onclick="this.nextElementSibling.open = !this.nextElementSibling.open">
Toggle Modal
</button>
<my-modal .open=${args.open}>
Some example content inside the modal
</my-modal>
`;
};
export const Modal: Story = Template.bind({});
Also, for boolean attributes - if implemented properly -
you should work with the property (prefix it in the template with a .) rather than the attribute.
Doing that with all native code isn't rocket science...
<my-dialog id="DIALOG" open>
Hello *Native* Web Components world!
</my-dialog>
<button onclick="DIALOG.open()">OPEN</button>
<script>
customElements.define("my-dialog", class extends HTMLElement {
static get observedAttributes() {
return ["open"];
}
constructor() {
super() // sets and returns 'this'
.attachShadow({mode:"open"}) // sets and return this.shadowRoot
.innerHTML = `<dialog><slot></slot><button>Close</button></dialog>`;
this.dialog = this.shadowRoot.querySelector("dialog");
}
connectedCallback() {
this.onclick = () => this.close(); // or attach to button
}
attributeChangedCallback(name,oldValue,newValue) {
this.open();
}
open() {
this.dialog.showModal(); // or .show()
}
close() {
this.dialog.close();
}
});
</script>
I have added the "Edit" button in the grid of the table for every row. The data for the table is coming from the api with the following JSON response.
{
Id: 1783
total: 2
trasfer: true
Sizing: true
name: "runner"
}
I am trying to implement when user clicks the edit button a new screen appears where one can edit the values of that row. So far I have implemented a button rendered component and alert when the button is click. How can I implement router to a new screen along with editable data of that particular row.
Demo: https://ag-grid2.zoltanhalasz.net/
button-renderer.component.ts
#Component({
selector: 'app-button-renderer',
template: `
<button type="button" (click)="onClick($event)">{{label}}</button>
`
})
export class ButtonRendererComponent implements ICellRendererAngularComp {
afterGuiAttached?(params?: import("ag-grid-community").IAfterGuiAttachedParams): void {
return;
}
ngAfterViewInit(): void {
return;
}
public params;
label: string;
constructor(){}
agInit(params: ICellRendererParams): void {
this.params = params;
this.label = this.params.label || null;
}
refresh(params: any): boolean {
return false;
}
public onClick(event) {
this.params.data[this.params.colDef.field] = event.checked;
if (typeof this.params.context.componentParent.notifyCellUpdate === "function"){
this.params.context.componentParent.CellUpdate(this.params);
}
}
}
app.component.ts
columnDef = [ {
headerName: 'Button', field : 'changeSettings',
cellRenderer: 'buttonRenderer',
cellStyle: {'text-align': 'center'},
cellRendererParams: {
label: 'Open'
}
} ]
CellUpdate(params){
if (params.colDef.field === "changeSettings"){
alert("Notified Button Clicked");
}
}
Create a component and navigate to it with input data.
There are many ways for transforming data between components.
Read this article
In your sample demo you should define route with an id and navigate to it's component then call an api to fetch the data.
Also you can open a modal to show the data instead.
Example:
CellUpdate(params){
if (params.colDef.field === "changeSettings"){
const modalRef = this.modalService.open(YourEditComponent);
modalRef.componentInstance.data= params;
}
}
How do I Create a non editable block with text in CKEditor 5.
I need something which in the final view generate a:
<div>Non editable message here</div>
I tried to use a UIElement and then set innerHTML but that still makes the element editable.
Just for reference: Her is the plugin I ended up using.
import Plugin from '#ckeditor/ckeditor5-core/src/plugin';
import DecoupledEditor from '#ckeditor/ckeditor5-editor-decoupled/src/decouplededitor';
import Essentials from '#ckeditor/ckeditor5-essentials/src/essentials';
import Paragraph from '#ckeditor/ckeditor5-paragraph/src/paragraph';
import Bold from '#ckeditor/ckeditor5-basic-styles/src/bold';
import Heading from '#ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '#ckeditor/ckeditor5-basic-styles/src/italic';
import ButtonView from '#ckeditor/ckeditor5-ui/src/button/buttonview';
import imageIcon from '#ckeditor/ckeditor5-core/theme/icons/image.svg';
import Command from '#ckeditor/ckeditor5-core/src/command';
import { downcastElementToElement,downcastAttributeToAttribute,downcastAttributeToElement } from '#ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
import { upcastElementToElement, upcastAttributeToAttribute,modelToViewAttributeConverter} from '#ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
import attachPlaceholder from "#ckeditor/ckeditor5-engine/src/view/placeholder";
import ViewPosition from '#ckeditor/ckeditor5-engine/src/view/position';
import toWidgetEditable from '#ckeditor/ckeditor5-widget/src/utils';
import ClickObserver from '#ckeditor/ckeditor5-engine/src/view/observer/clickobserver';
import UpcastDispatcher from '#ckeditor/ckeditor5-engine/src/conversion/upcastdispatcher';
import { toWidget } from '#ckeditor/ckeditor5-widget/src/utils';
export default class TestWidget2 extends Plugin {
static get pluginName() {
return 'TestWidget2';
}
init() {
console.log('TestWidget2::init()');
const editor=this.editor;
const model=editor.model;
model.schema.register( 'myWidget', {
inheritAllFrom: '$block',
isObject: true
} );
editor.conversion.for( 'dataDowncast' )
.add( downcastElementToElement( {
model: 'myWidget',
view: ( modelItem, writer ) => {
const elm=writer.createContainerElement( 'div', { class: 'widget' } );
return toWidget( div, writer, { label: 'widget label' } );
}
} ) );
editor.conversion.for( 'editingDowncast' )
.add( downcastElementToElement( {
model: 'myWidget',
view: ( modelItem, writer ) => {
const div = writer.createContainerElement( 'div', { class: 'widget' } );
return toWidget( div, writer, { label: 'widget label' } );
}
} ) );
editor.conversion.for( 'upcast' )
.add( upcastElementToElement( {
view: {
name: 'div',
class: 'widget'
},
model: 'myWidget'
} ) );
}
}
You can create the widget API for that:
import Widget from '#ckeditor/ckeditor5-widget/src/widget';
import { toWidget } from '#ckeditor/ckeditor5-widget/src/utils';
import { downcastElementToElement } from '#ckeditor/ckeditor5-engine/src/conversion/downcast-converters';
import { upcastElementToElement } from '#ckeditor/ckeditor5-engine/src/conversion/upcast-converters';
ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ Essentials, Paragraph, Widget, /* ... other plugins ... */ ],
toolbar: [ 'undo', 'redo' ]
} )
.then( editor => {
window.editor = editor;
const model = editor.model;
model.schema.register( 'myWidget', {
inheritAllFrom: '$block',
isObject: true
} );
editor.conversion.for( 'dataDowncast' )
.add( downcastElementToElement( {
model: 'myWidget',
view: ( modelItem, writer ) => {
return writer.createContainerElement( 'div', { class: 'widget' } );
}
} ) );
editor.conversion.for( 'editingDowncast' )
.add( downcastElementToElement( {
model: 'myWidget',
view: ( modelItem, writer ) => {
const div = writer.createContainerElement( 'div', { class: 'widget' } );
return toWidget( div, writer, { label: 'widget label' } );
}
} ) );
editor.conversion.for( 'upcast' )
.add( upcastElementToElement( {
view: {
name: 'div',
class: 'widget'
},
model: 'myWidget'
} ) );
editor.setData(
'<p>foobar</p>' +
'<div class="widget">Non editable text goes here</div>' +
'<p>foobar</p>'
);
} )
.catch( err => {
console.error( err.stack );
} );
The key point is to use the toWidget() function when downcasting an element to the editing view. Also, that element should be marked as an object in the schema.
Also don't forget to load the Widget plugin which turns on the support for widgets.
I just had the problem yesterday that when having a html table inside the isObject widget content, the table was still editable and also had controls.
The only way to fix it was to disable interaction inside my widget via css.
.ck-widget.my-wdiget *:not(.ck.ck-reset_all.ck-widget__type-around) {
pointer-events: none;
}
.ck.ck-reset_all.ck-widget__type-around is the class of the widget controls to add a linebreak before or after the widget. They are still usable.
I followed your steps without success..
For better knowledge (this guideline it's tested only in custom build for angular application but i think thats work everywhere)
probably you need use this command for follow correctly this guideline
npm install -g webpack
and in add to this you need install globally another dependency but i don't remember what is! (you can easly search the error on google for find it)
Create your custom build here
unzip, open folder and run npm install
install widget(with type def. if necessary) and core dependencies
npm i --save -D #ckeditor/ckeditor5-widget
npm i --save -D #types/ckeditor__ckeditor5-widget
npm i --save -D #ckeditor/ckeditor5-core
go into path src/ckeditor.js and add the following code for create the reinmar custom plugin
import {toWidget, Widget} from "#ckeditor/ckeditor5-widget";
import Plugin from '#ckeditor/ckeditor5-core/src/plugin';
class NotEditable extends Plugin {
init() {
const editor = this.editor;
const model = editor.model;
model.schema.register('myWidget', {
inheritAllFrom: '$block',
isObject: true
});
editor.conversion.for('dataDowncast')
.elementToElement({
model: 'myWidget',
view: (modelItem, writer) => {
return writer.writer.createContainerElement('div', {class: 'widget'});
}
});
editor.conversion.for('editingDowncast')
.elementToElement({
model: 'myWidget',
view: (modelItem, writer) => {
const div = writer.writer.createContainerElement('div', {class: 'widget'});
return toWidget(div, writer.writer, {label: 'widget label'});
}
});
editor.conversion.for('upcast')
.elementToElement({
view: {name: 'div', class: 'widget'},
model: 'myWidget'
});
}
}
and in Editor.builtinPlugins add Widget and NotEditable
Editor.builtinPlugins = [
//***other plugin,
Widget,
NotEditable
];
exec in the terminal npm run build
copy the build folder into your project and import the build (follow official Ckeditor5 guideline for this) {in my case i follow this guideline in angular guide}
According to the documentation isReadOnly : Boolean
Set it to true.
Official Documentation
I want to update/re-render the component after a new update comes up. All I am doing is:
I have a list of dealers for a casino game, what I want is to add a new dealer, and once the new dealer is added then display it in the view. It is actually happening, but in order for me to see the new dealer, I have to reload the page.
I am not updating the state, I am working with this.props. Look at my code
#connectToStores
export default class Dealers extends Component {
constructor (props) {
super(props);
this.state = {}
}
componentWillMount () {
GetDealersActions.getDealers();
}
static getStores () {
return [ GetDealersStore, CreateDealersStore ];
}
static getPropsFromStores () {
return {
...GetDealersStore.getState(),
...CreateDealersStore.getState(),
}
}
render () {
return (
<div>
{!!this.props.dealerData ?
this.props.dealerData.dealersData.map((dealer) => {
return (here I am rendering what I need);
: <p>Loading . . .</p>
</div>
}
_addDealer = () => {
CreateDealersActions.createDealer({
DealerName : this.refs.DealerName.getValue(),
CardId : this.refs.CardId.getValue(),
NickName : this.refs.NickName.getValue(),
});
}
}
as you see the component above in the code is doing the initial rendering properly, the problem comes up when you hit _addDealer(), which is not updating the component, you should reload the page in order to see the new item in the view.
If you do a console.log(this.props); within _addDealer(), you will get something like this
{params: Object, query: Object, dealerData: Object, newDealerData: null}
where dealerData holds the full data of the dealers in the view but you can't see there the new dealer created. And newDealerData remains null
so, what do you think I should do in order to update the component everytime a new prop/dealer comes up ? or how do I update the props? which is the proper method in this situation ?
here is the full code for stores and actions just in case
action
#createActions(flux)
class CreateDealersActions {
constructor () {
this.generateActions('createDealerSuccess', 'createDealerFail');
}
createDealer (data) {
const that = this;
that.dispatch();
axios.post(`${API_ENDPOINT}/create-dealer/create-dealer`, data)
.then(function success (data) {
that.actions.createDealerSuccess({data});
})
}
};
store
#createStore(flux)
class CreateDealersStore {
constructor () {
this.state = {
newDealerData : null,
};
}
#bind(CreateDealersActions.createDealerSuccess)
createDealerSuccess (data) {
this.setState({
newDealerData : data.response.config.data,
});
}
}
the Dealers component is within a tab named management, which is this one:
const menuItems = [
{ route : 'dealers', text : 'Dealers' },
{ route : 'game-info', text : 'Game Info' },
{ route : 'player-info', text : 'Players Info' },
{ route : 'money', text : 'Money' }
];
export default class Management extends React.Component {
static propTypes = {
getActivePage : React.PropTypes.func,
menuItems : React.PropTypes.arrayOf(React.PropTypes.object),
}
static contextTypes = {
router : React.PropTypes.func,
}
render () {
return (
<div>
<TabsMainMenu menuItems={menuItems} getActivePage={this._getActivePage} />
<RouteHandler />
</div>
);
}
_getActivePage = () => {
for (const i in menuItems) {
if (this.context.router.isActive(menuItems[i].route)) return parseInt(i, 10);
}
}
}