In this demo there's a dropdown with the options "Heading 1", "Heading 2" and "Normal". I'm looking for a way to customize that with my own options (or adding a new button instead of dropdowns) using div classes. For example, I want to add a new option called "myThing" and it turns this:
<p>Lorem ipsum dolor sit amet</p>
into this:
<div class="myThing">Lorem ipsum dolor sit amet</div>
How do I do that?
You can do this by extending the block blot. As shown in the this section of the Quilljs guides. Just extend the block blot, and set your tag and class name. Example:
var Block = Quill.import('blots/block');
class MyThing extends Block {}
MyThing.blotName = 'my-thing';
MyThing.className = 'my-thing';
MyThing.tagName = 'div';
Quill.register(MyThing);
var quill = new Quill('#editor', {
theme: 'snow',
modules: {
toolbar: [
['my-thing']
]
}
});
.ql-toolbar .ql-my-thing {
width: 60px !important;
}
.ql-toolbar .ql-my-thing:before {
content: 'My Thing';
}
.my-thing {
background: #f00;
color: #fff;
}
<link href="https://cdn.quilljs.com/1.3.4/quill.snow.css" rel="stylesheet">
<script src="https://cdn.quilljs.com/1.3.4/quill.js"></script>
<div id="editor">
<p>Hello World!</p>
<p>Some initial <strong>bold</strong> text</p>
<p><br></p>
</div>
Related
I know you can easily toggle a class like this:
.c {
padding: 20px;
background: #00adff;
}
.a {
background: #43dd31;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="">
<div class="c" ng-class="{'a': toggle }">
<button ng-click="toggle = !toggle">Toggle</button>
</div>
</div>
My question is, what if I have two separate classes I want to toggle with different buttons on the same div using this method?
AngularJS allows you to define numerous classes in the map-format. Following is a demo to toggle a class b using a second button.
.c {
padding: 20px;
background: #00adff;
}
.a {
background: #43dd31;
}
.b {
border: 5px dashed yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="">
<div class="c" ng-class="{'a': toggle, b: secondToggle}">
<button ng-click="toggle = !toggle">Toggle</button>
<button ng-click="secondToggle = !secondToggle">Second Toggle</button>
</div>
</div>
I am learning angularjs and I came across some behaviour that I can't understand. I render a list of items in ng-repeat, each has a button to remove itself from the $scope's array - this works as expected but once I added a sortable to the list strange things started to happen.
Here is the running example showing the issue:
https://embed.plnkr.co/eQWcxZ7p8CcACfk6Z53X/
In the example - if I move [^] item 4 (Rocket Launcher) to position 1 and use Rocket Launcher's delete [X] button the list gets updated (i.e. item 4 - Rocket Launcher - that was on position 1 is removed) but the other items delete buttons stop working. Basically moving items and deleting them somehow break the bindings (?).
The code:
(function() {
'use strict';
var app = angular.module('myApp', []);
app.controller('myAppController', function($scope) {
$scope.boxes = [];
$scope.removeBoxItem = function(box, item) {
console.log('Removing "' + item.name + '" form box "' + box.name + '"...');
var index = box.items.indexOf(item);
box.items.splice(index, 1);
console.log(box);
};
this.init = function() {
var e;
e = new Box({
name: 'Red box'
});
$scope.boxes.push(e);
e.items.push(new Item({
index: 1,
name: 'Rock'
}));
e.items.push(new Item({
index: 2,
name: 'Scissors'
}));
e.items.push(new Item({
index: 3,
name: 'Paper'
}));
e.items.push(new Item({
index: 4,
name: 'Rocket launcher'
}));
e = new Box({
name: 'Green box'
});
e.items.push(new Item({
index: 1,
name: 'Chuck the Plant'
}));
e.items.push(new Item({
index: 2,
name: 'Hamster'
}));
e.items.push(new Item({
index: 3,
name: 'Tentacle Chow'
}));
$scope.boxes.push(e);
};
this.init();
});
app.directive("sortable", ["$timeout", function($timeout) {
return {
template: '<div class="sortable" ng-transclude></div>',
transclude: true,
scope: {
'handle': '#'
},
link: function(scope, element, attrs) {
$timeout(function() {
//console.log(element)
var sortable = element.find('> div');
console.log(sortable[0]);
scope.sortable = Sortable.create(sortable[0], {
handle: scope.handle || null
});
});
}
};
}]);
}());
function Box(args) {
this.name = args.name || null;
this.items = [];
}
function Item(args) {
this.index = args.index || null;
this.name = args.name || null;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="style.css" />
<style>
.container {
border: 1px solid #929292;
padding: 5px;
}
.header {
font-size: 1.2rem;
padding: 10px 15px;
background-color: #F5F5F5;
border-bottom: 2px solid #E2E2E2;
}
.body {
background-color: #F2F2F2;
padding: 10px 10px;
margin-bottom: 10px;
}
.body .item {
border: 1px solid #D2D2D2;
padding: 5px;
margin-bottom: 5px;
}
.body .options {
float: right;
}
.body .options .delete {
cursor: pointer;
}
.body .options .handle {
cursor: move;
}
.debug {
margin-top: 20px;
border-top: 1px dotted #929292;
}
</style>
</head>
<body>
<div ng-app="myApp" ng-controller="myAppController as appCtrl">
<div class="container">
<div ng-repeat="box in boxes">
<div class="header">{{ box.name }}</div>
<div class="body">
<div data-sortable="" data-handle=".handle">
<div class="item" ng-repeat="item in box.items">
{{item.index }}) {{ item.name }}
<div class="options">
<span ng-click="removeBoxItem(box, item)" class="delete">[X]</span>
<span class="handle">[^]</span>
</div>
</div>
</div>
</div>
</div>
<div class="debug">
<pre>{{ boxes | json }}
</pre>
</div>
</div>
</div>
<script data-require="jquery#3.1.1" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script data-require="Sortable.js#1.6.0" data-semver="1.6.0" src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.6.0/Sortable.js"></script>
<script data-require="angular.js#1.6.6" data-semver="1.6.6" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.js"></script>
<script src="script.js"></script>
</body>
</html>
I am confused by this, in my real code things get even more broken - I made a collapsible directive that surrounds the "Boxes" so I can open and manipulate one at a time - in that case moving item 4 to position 1 and deleting it removes all items from the view (but not from the $scope). Than adding new item to the $scope's array causes items to correctly reappear. For now I created simpler version as I guess this is all somehow connected.
I am aware the sortable should set the objects indexes etc but for now I'd like to understand what is happening. I suspect I have some issues with understanding what is going on with scopes (?). Would be grateful for any help.
I am using multiple ui-grid, wants to edit ui-grid-row class for one grid only.
but its reflecting to all.
Code
I want height of row should be auto for second grid only.
I applied CSS as
.gridR.ui-grid-row{height: auto!important;}
.gridR.ui-grid-row > div { display: table-row;}
.gridR.ui-grid-row > div .ui-grid-cell {display: table-cell;float: none;vertical-align: middle; height: auto!important;}
.gridR.ui-grid-cell-contents{ white-space: normal; text-overflow: inherit;word-break: break-word;}
but nothing happened.
Can someone help on this.
Thanks
This should do it:
var app = angular.module('app', ['ui.grid']);
app.controller('MainCtrl', ['$scope',
function($scope) {
var aLotOfData = [{
"LongString": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
}];
aLotOfData.push(aLotOfData[0]);
aLotOfData.push(aLotOfData[0]);
aLotOfData.push(aLotOfData[0]);
$scope.gridOptionsL = {
columnDefs: [{name: 'LongString', displayName: 'Default Style'}],
data: aLotOfData
};
$scope.gridOptionsR = {
columnDefs: [{name: 'LongString', displayName: 'Your Style'}],
data: aLotOfData
};
}
]);
div[ui-grid] {
height: 180px;
width: 300px;
float: left;
}
.gridR .ui-grid-row {
height: auto!important;
}
.gridR .ui-grid-row>div {
display: table-row;
}
.gridR .ui-grid-row>div .ui-grid-cell {
display: table-cell;
float: none;
vertical-align: middle;
height: auto!important;
}
.gridR .ui-grid-cell-contents {
white-space: normal;
text-overflow: inherit;
word-break: break-word;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.1/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.2/ui-grid.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/angular-ui-grid/4.0.2/ui-grid.min.css" />
<div ng-app="app" ng-controller="MainCtrl">
<div ui-grid="gridOptionsL" class="grid gridL"></div>
<div ui-grid="gridOptionsR" class="grid gridR"></div>
</div>
(without seeing your HTML I can only guess - but I basically ADDED a gridR class rather than just adding an R to the existing grid class)
Hope that helps, let me know if you have any further questions.
I'm cutting my teeth with Google Polymer by trying to put together a control panel style layout but unfortunately when clicking on items in my app-drawer the content doesn't load in the main field. The url updates in the bar and the CSS highlights the selection but nothing else happens.
I started with a blank app template using polymer init, tried to flesh out the structure by referencing this answer, and then referenced the starter-kit as a guide for the rest. If anyone could give me a nudge in the right direction it would be greatly appreciated as i'm still new to the concepts of routing.
<dom-module id="Panel-app">
<template>
<style>
:host {
display: block;
font-family: Fira Sans Condensed;
--app-primary-color: #1A3663;
}
app-header {
background-color: var(--app-primary-color);
color: white;
}
app-drawer {
top: 64px;
--app-drawer-content-container: {
padding: 0px;
background-color: #325999;
};
}
.drawer-list {
margin: 0 20px;
}
.drawer-list a {
display: block;
padding: 0 16px;
text-decoration: none;
color: var(--app-secondary-color);
line-height: 40px;
}
.drawer-list a.iron-selected {
color: black;
font-weight: bold;
}
</style>
<app-location route="{{route}}"></app-location>
<app-route
route="{{route}"
pattern="/:page"
data="{{routeData}}"
tail="{{subroute}}"></app-route>
<app-header-layout fullbleed>
<app-header shadow>
<app-toolbar id="toolbar">
<paper-icon-button icon="menu" onclick="drawer.toggle()"></paper-icon-button>
<div main-title>Panel</div>
<paper-menu-button>
<paper-icon-button icon="communication:live-help" class="dropdown-trigger"></paper-icon-button>
<paper-menu class="dropdown-content">
<paper-item>Live Chat</paper-item>
<paper-item>Contact List</paper-item>
<paper-item>Leave Feedback</paper-item>
</paper-menu>
</paper-menu-button>
<paper-icon-button icon="supervisor-account" class="dropdown-trigger"></paper-icon-button>
<paper-icon-button icon="settings" class="dropdown-trigger"></paper-icon-button>
</app-toolbar>
</app-header>
<app-drawer-layout>
<app-drawer id="drawer">
<iron-selector selected="[[page]]" attr-for-selected="name" class="drawer-list" role="navigation">
<a name="view1" href="/view1">One</a>
<a name="view2" href="/view2">Two</a>
<a name="view3" href="/view3">Three</a>
</iron-selector>
</app-drawer>
<iron-pages
selected="[[page]]"
attr-for-selected="name"
fallback-selection="view404"
role="main">
<my-view1 name="view1"></my-view1>
<my-view2 name="view2"></my-view2>
<my-view3 name="view3"></my-view3>
</iron-pages>
</app-drawer-layout>
</app-header-layout>
</template>
<script>
Polymer({
is: 'Panel-app',
properties: {
page: {
type: String,
reflectToAttribute: true,
observer: '_pageChanged',
},
},
observers: [
'_routePageChanged(routeData.page)',
],
_routePageChanged: function(page) {
this.page = page || 'view1';
if (!this.$.drawer.persistent) {
this.$.drawer.close();
}
},
_pageChanged: function(page) {
// Load page import on demand. Show 404 page if fails
var resolvedPageUrl = this.resolveUrl('my-' + page + '.html');
this.importHref(resolvedPageUrl, null, this._showPage404, true);
},
_showPage404: function() {
this.page = 'view404';
},
});
</script>
</dom-module>
You're missing a curly bracket here or else the binding fails:
route="{{route}"
It must be
route="{{route}}"
Then the _routePageChanged observer works
I installed malhar-angular-dashboard module for my angular application and I want to create a simple widget that displays some dummy text.
HTML view
<div class="row">
<div class="col-md-12">
<div dashboard="timeDashboardsOptions" class="dashboard-container"></div>
</div>
</div>
JavaScript
$scope.timeDashboardsOptions = {
widgetDefinitions: [ // list required
{
name: 'timeWidget', // option required
template: '<div>hello {{widget.title}}</div>',
settingsModalOptions: {
templateUrl: 'views/dashboards/widget-area/time.html'
}
,
onSettingsClose: function(resultFromModal, widgetModel, dashboardScope) {
// do something to update widgetModel, like the default implementation:
jQuery.extend(true, widget, result);
},
onSettingsDismiss: function(reasonForDismissal, dashboardScope) {
// probably do nothing here, since the user pressed cancel
}
}
],
defaultWidgets: [ // list required
{name:'timeWidget'}
]
};
Widget template
<div>
<h3>Time widget</h3>
</div>
When I run it, I get this kind of result:
ul li {
list-style-type: none;
display: inline;
}
.middle {
color: #fff;
background-color: #f0ad4e;
border-color: #eea236;
}
.last {
background-color: #5bc0de;
border-color: #46b8da;
}
<ul>
<li class='first'>timeWidget - missing ???</li>
<li>
<button class='middle'>Default Widgets</button>
</li>
<li class='last'>
<button class='last'>Clear</button>
</li>
</ul>
and the error
TypeError: _.merge is not a function
at Object.WidgetModel (http://localhost:9000/bower_components/malhar-angular-dashboard/dist/malhar-angular-dashboard.js:848:42)
Remove underscore.js and let loadash.js handle it.