Skip to content
Advertisement

Copy and Paste Table Using ContentEditable

This video is a good representation of the issue I am facing: https://drive.google.com/file/d/1jN44lUpnbVDv_m3LuPhlJl6RFUu884jz/view. I cannot copy and paste a table from another a tab without it breaking down. Because this uses local storage, here is a JSFiddle: https://jsfiddle.net/znj537w0/1/.

var app = angular.module("TodoApp", ["LocalStorageModule", 'ngSanitize']);
app.controller("TodoController", function ($scope, localStorageService) {
    if (!localStorageService.get("taskListActive")) {
        $scope.tasksActive = [{
            text: "Do me next",
            priority: 1,
            complete: false
        },
        {
            text: "I'm not important",
            priority: 0,
            complete: false
        }
        ];
    } else {
        $scope.tasksActive = localStorageService.get("taskListActive");
    }

    if (!localStorageService.get("taskListComplete")) {
        $scope.tasksComplete = [{
            text: "I'm already done",
            priority: 0,
            complete: true
        }];
    } else {
        $scope.tasksComplete = localStorageService.get("taskListComplete");
    }

    $scope.totalTasks = function () {
        console.log($scope.tasksComplete.length);
        return $scope.tasksActive.length + $scope.tasksComplete.length;
    };

    $scope.totalRemaining = function () {
        return $scope.tasksActive.length;
    };

    $scope.totalComplete = function () {
        return $scope.tasksActive.length;
    };

    $scope.todoAdd = function () {
        if ($scope.taskInput.name) {
            $scope.tasksActive.unshift({
                text: $scope.taskInput.name,
                priority: $scope.taskInput.priority || 0,
                complete: false
            });
            $scope.taskInput.name = "";
            $scope.taskInput.priority = 0;
        }
    };

    $scope.togglePriority = function (task) {
        if (task.priority === 0) {
            task.priority = 1;
            console.log("a");
        } else {
            task.priority = 0;
        }
    };

    $scope.completeTask = function (task) {
        //var task = $scope.tasksActive[index];
        task.complete = true;
        task.priority = 0;
        $scope.tasksActive.splice($scope.tasksActive.indexOf(task), 1);
        $scope.tasksComplete.unshift(task);
    };

    $scope.uncompleteTask = function (task) {
        task.complete = false;
        $scope.tasksComplete.splice($scope.tasksComplete.indexOf(task), 1);
        $scope.tasksActive.unshift(task);
    };

    $scope.deleteTask = function (task, list) {
        if (list == "active") {
            $scope.tasksActive.splice($scope.tasksActive.indexOf(task), 1);
        } else {
            $scope.tasksComplete.splice($scope.tasksComplete.indexOf(task), 1);
        }
    };

    $scope.clearCompleted = function () {
        var deleteArr = [];
        for (var i = 0; i < $scope.tasksComplete.length; i++) deleteArr.push(i);
        for (var i = 0; i < deleteArr.length; i++) {
            var task = i;
            $scope.tasksComplete.splice($scope.tasksComplete.indexOf(task) - 1, 1);
        }
    };

    $scope.$watch(
        "tasksActive",
        function (newVal, oldVal) {
            console.log("tasksActive");
            if (newVal !== null && angular.isDefined(newVal) && newVal !== oldVal) {
                localStorageService.add("taskListActive", angular.toJson(newVal));
            }
        },
        true
    );

    $scope.$watch(
        "tasksComplete",
        function (newVal, oldVal) {
            console.log("tasksComplete");
            if (newVal !== null && angular.isDefined(newVal) && newVal !== oldVal) {
                localStorageService.add("taskListComplete", angular.toJson(newVal));
            }
        },
        true
    );

    $scope.contentEdit = function (event, task) {
        const newText = event.target.innerText;
        if (newText && task) {
            task.text = newText;
            console.log(event.target.innerText);
        }
    }
});

const newText = event.target.innerHTML;
*,
*:before,
*:after {
  box-sizing: border-box;
}

.max-width {
  max-width: 600px;
}

.centered {
  margin: auto;
}

.text-center-h {
  text-align: center;
}

.text-left {
  text-align: left;
}

.text-right {
  text-align: right;
}

.list-no-style {
  list-style: none outside none;
  padding-left: 0;
}

html,
body {
  width: 100%;
  min-height: 100%;
  color: #333;
  padding: 20px 20px 20px 10px;
}

html {
  font-size: 10px;
}

body {
  font-size: 1.6rem;
  background: linear-gradient(45deg, #bbdefb 0%, #311b92 100%);
}

p {
  white-space: pre-wrap;
  margin: 1em;
  color: #777;
}

.block {
  font-size: 0;
  margin-bottom: 24px;
}

.block>* {
  font-size: medium;
  display: inline-block;
  vertical-align: top;
}

.block-justify {
  text-align: justify;
}

.block-justify:after {
  content: '';
  display: inline-block;
  width: 100%;
}

.block-justify>* {
  display: inline-block;
  vertical-align: top;
}

.block-table {
  display: table;
  table-layout: fixed;
  width: 100%;
}

.block-table>* {
  display: table-cell;
}

.fa {
  font-size: 2rem;
  color: #bbb;
  padding: 0 6px;
  transition: color 0.2s ease;
}

.fa.-clickable {
  cursor: pointer;
}

button.-add,
.btn.-add {
  border: none;
  padding: 5px 0 0;
  border-bottom: 3px solid #0eb2f0;
  background: #56c9f5;
  transition: all 0.1s ease;
}

button.-add:hover,
.btn.-add:hover {
  background: #6ed1f6;
}

button.-add:active,
.btn.-add:active {
  border-bottom-width: 1px;
}

button.-clear,
.btn.-clear {
  border: none;
  padding: 0;
  background: none;
  color: #bbb;
}

button.-clear:hover,
.btn.-clear:hover {
  color: tomato;
}

.task-list._wrap {
  background: #fff;
  padding: 20px;
  margin-top: 50px;
  margin-bottom: 50px;
  box-shadow: 18px 18px 0 0 #56c9f5;
}

.task-list._wrap h1 {
  font-size: 5rem;
}

.totals._wrap,
.search {
  vertical-align: bottom;
}

.totals._wrap {
  font-size: 0;
}

.totals._grand-total,
.totals._detail {
  display: inline-block;
  vertical-align: top;
  font-size: medium;
}

.totals._grand-total {
  text-align: center;
  height: 90px;
  padding: 6px 12px;
  background: #64b5f6;
  color: #fff;
  overflow: hidden;
}

.totals._grand-total span {
  display: block;
}

.totals._total-number {
  font-size: 3rem;
}

.totals._detail p {
  height: 60px;
  padding: 3px 6px;
}

.search._wrap {
  position: relative;
}

.search .fa {
  position: absolute;
  left: 3px;
  top: 50%;
  transform: translateY(-50%);
}

.search input.-text {
  padding-left: 30px;
}

.add-form._wrap {
  position: relative;
  height: 80px;
  padding: 12px;
  border: 1px solid #694ede;
  box-shadow: 3px 3px 0 0 #694ede;
}

.add-form input[type="text"] {
  width: 100%;
}

.add-form._buttons {
  position: absolute;
  right: 12px;
  padding: 2px;
  width: 180px;
  font-size: 0;
}

.add-form._checkbox-wrap,
.add-form._submit-button {
  display: inline-block;
  vertical-align: middle;
  font-size: medium;
  height: 100%;
}

.add-form._checkbox {
  padding: 0 12px;
}

.add-form._checkbox input {
  visibility: hidden;
}

.add-form._checkbox .fa:hover {
  color: #7b7b7b;
}

.add-form._checkbox input:checked+.fa {
  color: tomato;
}

.add-form._submit-button {
  height: 42px;
  padding: 0 20px;
}

input.-text {
  padding: 6px 12px;
  height: 46px;
}

input.-add-task {
  border: none;
  border: 2px solid #64b5f6;
}

input.-search {
  border: 2px solid #64b5f6;
}

.task._item {
  background: #fff;
  box-shadow: 3px 3px 0 0;
  border: 1px solid;
  overflow: auto;
  margin-bottom: 6px;
}

.task._item a {
  text-decoration: none;
}

.task.-done-false {
  color: #56c9f5;
}

.task.-done-false p,
.task.-done-false a {
  color: #333;
}

.task.-done-true {
  color: #d5d5d5;
}

.task.-done-true p,
.task.-done-true a {
  color: #bbb;
}

.task._task-left,
.task._task-right {
  height: 66px;
  padding: 10px;
}

.task._task-left {
  width: calc(100% - 180px);
  margin-bottom: 15px;
  height: 100px;
  overflow: auto;
}

.task._task-right {
  width: 180px;
  overflow: auto;
}

.task._task-right .btn {
  display: inline-block;
  margin-top: 3px;
  margin-bottom: 15px;
}

.task._task-right .btn.-priority:hover .fa {
  color: #7b7b7b;
}

.task._task-right .btn.-complete:hover .fa,
.task._task-right .btn.-re-open:hover .fa {
  color: #0eb2f0;
}

.task._task-right .btn.-clear:hover .fa {
  color: tomato;
}

.task.-task-priority-high ._task-left {
  padding-left: 28px;
  position: relative;
}

.task.-task-priority-high ._task-left:before {
  position: absolute;
  content: '';
  width: 6px;
  top: 12px;
  bottom: 12px;
  left: 12px;
  background: tomato;
}

.task.-task-priority-high .btn.-priority .fa {
  color: tomato;
}

p {
  margin: 1em;
  color: #777;
}

p.changed {
  color: black;
}

button {
  margin: 0 1em;
}

.btn {
  display: inline-block;
  *display: inline;
  padding: 4px 10px 4px;
  margin-bottom: 0;
  *margin-left: 0.3em;
  font-size: 13px;
  line-height: 18px;
  *line-height: 20px;
  color: #333;
  text-align: center;
  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
  vertical-align: middle;
  cursor: pointer;
  background-color: #f5f5f5;
  *background-color: #e6e6e6;
  background-image: -ms-linear-gradient(top, #fff, #e6e6e6);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fff), to(#e6e6e6));
  background-image: -webkit-linear-gradient(top, #fff, #e6e6e6);
  background-image: -o-linear-gradient(top, #fff, #e6e6e6);
  background-image: linear-gradient(top, #fff, #e6e6e6);
  background-image: -moz-linear-gradient(top, #fff, #e6e6e6);
  background-repeat: repeat-x;
  border: 1px solid #ccc;
  *border: 0;
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
  border-bottom-color: #b3b3b3;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  border-radius: 4px;
  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
  *zoom: 1;
  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
}

.btn:hover {
  background-color: #e6e6e6;
  *background-color: #d9d9d9;
  color: #333;
  text-decoration: none;
  background-color: #e6e6e6;
  *background-color: #d9d9d9;
  background-position: 0 -15px;
  -webkit-transition: background-position 0.1s linear;
  -moz-transition: background-position 0.1s linear;
  -ms-transition: background-position 0.1s linear;
  -o-transition: background-position 0.1s linear;
  transition: background-position 0.1s linear;
}

.btn:active {
  background-color: #e6e6e6;
  *background-color: #d9d9d9;
  background-color: #ccc 9;
  background-color: #e6e6e6;
  background-color: #d9d9d9 9;
  background-image: none;
  outline: 0;
  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
  -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
}

.btn:first-child {
  *margin-left: 0;
}

.btn:focus {
  outline: thin dotted #333;
  outline: 5px auto -webkit-focus-ring-color;
  outline-offset: -2px;
}

.btn.active {
  background-color: #e6e6e6;
  *background-color: #d9d9d9;
  background-color: #ccc 9;
  background-color: #e6e6e6;
  background-color: #d9d9d9 9;
  background-image: none;
  outline: 0;
  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
  -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
  box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
}

.btn.disabled {
  background-color: #e6e6e6;
  *background-color: #d9d9d9;
}

.btn[disabled] {
  background-color: #e6e6e6;
  *background-color: #d9d9d9;
}

.btn-primary {
  background-color: #0074cc;
  *background-color: #05c;
  background-image: -ms-linear-gradient(top, #08c, #05c);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#08c), to(#05c));
  background-image: -webkit-linear-gradient(top, #08c, #05c);
  background-image: -o-linear-gradient(top, #08c, #05c);
  background-image: -moz-linear-gradient(top, #08c, #05c);
  background-image: linear-gradient(top, #08c, #05c);
  background-repeat: repeat-x;
  border-color: #05c #05c #003580;
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);
  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-primary:hover {
  background-color: #05c;
  *background-color: #004ab3;
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-primary:active {
  background-color: #05c;
  *background-color: #004ab3;
  background-color: #004099 9;
}

.btn-primary.active {
  background-color: #05c;
  *background-color: #004ab3;
  background-color: #004099 9;
  color: rgba(255, 255, 255, 0.75);
}

.btn-primary.disabled {
  background-color: #05c;
  *background-color: #004ab3;
}

.btn-primary[disabled] {
  background-color: #05c;
  *background-color: #004ab3;
}

.btn-warning {
  background-color: #faa732;
  *background-color: #f89406;
  background-image: -ms-linear-gradient(top, #fbb450, #f89406);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
  background-image: -o-linear-gradient(top, #fbb450, #f89406);
  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
  background-image: linear-gradient(top, #fbb450, #f89406);
  background-repeat: repeat-x;
  border-color: #f89406 #f89406 #ad6704;
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-warning:hover {
  background-color: #f89406;
  *background-color: #df8505;
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-warning:active {
  background-color: #f89406;
  *background-color: #df8505;
  background-color: #c67605 9;
}

.btn-warning.active {
  background-color: #f89406;
  *background-color: #df8505;
  background-color: #c67605 9;
  color: rgba(255, 255, 255, 0.75);
}

.btn-warning.disabled {
  background-color: #f89406;
  *background-color: #df8505;
}

.btn-warning[disabled] {
  background-color: #f89406;
  *background-color: #df8505;
}

.btn-danger {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-danger:hover {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-success {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-success:hover {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-info {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-info:hover {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-inverse {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-inverse:hover {
  color: #fff;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
}

.btn-danger.active {
  color: rgba(255, 255, 255, 0.75);
}

.btn-success.active {
  color: rgba(255, 255, 255, 0.75);
}

.btn-info.active {
  color: rgba(255, 255, 255, 0.75);
}

.btn-inverse.active {
  color: rgba(255, 255, 255, 0.75);
}
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.8.0/angular.min.js">
</script>
<script type="text/javascript" src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/131045/ngLocalStorage.js">
</script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
</link>
<div ng-app="TodoApp" ng-controller="TodoController" class="task-list _wrap centered max-width text-center-h ng-scope"style="font-family: Arial, sans-serif;">
    <h1 style="font-family: Arial, sans-serif;">Notes:</h1>
    <div class="block-justify" style="position: relative; left: -153px; top: -14px;">
        <div class="totals _wrap text-left">
            <div class="totals _detail">


            </div>
        </div>
        <div class="search _wrap text-right">
            <input class="input -text -search" type="text" placeholder="Search tasks" ng-model="taskSearch.name" />
            <i class="fa fa-search"></i>
        </div>
    </div>

    <form class="add-form _wrap block text-left">
        <input class="input -text -add-task" type="text" placeholder="Add a new task" ng-model="taskInput.name" ng-model-instant />
        <div class="add-form _buttons text-right">
            <p>Priority</p>
            <div class="add-form _checkbox-wrap">
                <label class="add-form _checkbox"><input class="input -checkbox" type="checkbox" name="priority"
                                ng-model="taskInput.priority" ng-init="checked=false" parse-int ng-true-value="1"
                                ng-false-value="0"></i></label>
            </div>
<button class="add-form _submit-button btn -add" ng-click="todoAdd()" style="position: relative; left: 18px; top: -3px; height: 47px; transform-origin: 50% 78%;">Add</button>
        </div>
    </form>

    <ul class="list-no-style text-left">
        <li ng-repeat="task in tasksActive | filter:taskSearch.name | orderBy:'-priority'"
            class="task _item -done-{{ task.complete }} -task-priority-{{ task.priority==true ? 'high' : 'low' }} block-table">
            <div class="task _task-left" ;>
                <p id="myText" contenteditable class="changed"
                ng-on-blur="contentEdit($event, task)" 
                ng-bind-html="task.text"></p>
            </div>
            <div class="task _task-right text-right">
                <a href ng-click="togglePriority(task)" class="btn -task-action -priority"
                    title="Change priority"><i class="fa fa-exclamation"></i></a>
                <a href ng-click="completeTask(task)" class="btn -task-action -complete" title="Complete"><i
                                class="fa fa-check"></i></a>
                <a href ng-click="deleteTask(task,'active')" class="btn -clear" title="Delete"><i
                                class="fa fa-times-circle"></i></a>

            </div>
        </li>
        <li ng-repeat="task in tasksComplete | filter:taskSearch.name"
            class="task _item -done-{{ task.complete }} block">
            <p style="white-space: pre-wrap;" class="task _task-left">{{ task.text }}</p>
            <div class="task _task-right text-right">
                <a href ng-click="uncompleteTask(task)" class="btn -task-action -re-open" title="Re-open"><i
                                class="fa fa-undo"></i></a>
                <a href ng-click="deleteTask(task,'complete')" class="btn -clear" title="Delete"><i
                                class="fa fa-times-circle"></i></a>
            </div>
        </li>
    </ul>

    <form class="text-right">
        <button class="btn -clear" ng-show="tasksComplete.length" ng-click="clearCompleted()">Delete all
                    completed</button>
    </form>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.8.0/angular-sanitize.min.js"></script>

Advertisement

Answer

Use this:

$scope.contentEdit = function (event, task) {
        const newText = event.target.innertHTML;
        if (newText && task) {
            task.text = newText;
        }
    }

Change innerText to innerHTML. https://jsfiddle.net/3uvfjdew/

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement